2021-07-24 11:16:34 +01:00
// Copyright 2021 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2021-07-24 11:16:34 +01:00
2024-10-02 08:03:19 +08:00
package oauth2_provider //nolint
2021-07-24 11:16:34 +01:00
import (
"fmt"
"time"
"code.gitea.io/gitea/modules/timeutil"
2021-11-17 20:34:35 +08:00
2023-07-19 04:57:10 -05:00
"github.com/golang-jwt/jwt/v5"
2021-07-24 11:16:34 +01:00
)
// Token represents an Oauth grant
2024-10-02 08:03:19 +08:00
// TokenKind represents the type of token for an oauth application
type TokenKind int
2021-07-24 11:16:34 +01:00
const (
2024-10-02 08:03:19 +08:00
// KindAccessToken is a token with short lifetime to access the api
KindAccessToken TokenKind = 0
// KindRefreshToken is token with long lifetime to refresh access tokens obtained by the client
KindRefreshToken = iota
2021-07-24 11:16:34 +01:00
)
// Token represents a JWT token used to authenticate a client
type Token struct {
GrantID int64 ` json:"gnt" `
2024-10-02 08:03:19 +08:00
Kind TokenKind ` json:"tt" `
2021-07-24 11:16:34 +01:00
Counter int64 ` json:"cnt,omitempty" `
2022-01-20 21:52:56 +00:00
jwt . RegisteredClaims
2021-07-24 11:16:34 +01:00
}
// ParseToken parses a signed jwt string
2021-08-27 21:28:00 +02:00
func ParseToken ( jwtToken string , signingKey JWTSigningKey ) ( * Token , error ) {
2023-07-04 20:36:08 +02:00
parsedToken , err := jwt . ParseWithClaims ( jwtToken , & Token { } , func ( token * jwt . Token ) ( any , error ) {
2021-08-27 21:28:00 +02:00
if token . Method == nil || token . Method . Alg ( ) != signingKey . SigningMethod ( ) . Alg ( ) {
2021-07-24 11:16:34 +01:00
return nil , fmt . Errorf ( "unexpected signing algo: %v" , token . Header [ "alg" ] )
}
2021-08-27 21:28:00 +02:00
return signingKey . VerifyKey ( ) , nil
2021-07-24 11:16:34 +01:00
} )
if err != nil {
return nil , err
}
2023-07-19 04:57:10 -05:00
if ! parsedToken . Valid {
return nil , fmt . Errorf ( "invalid token" )
}
2021-07-24 11:16:34 +01:00
var token * Token
var ok bool
if token , ok = parsedToken . Claims . ( * Token ) ; ! ok || ! parsedToken . Valid {
return nil , fmt . Errorf ( "invalid token" )
}
return token , nil
}
// SignToken signs the token with the JWT secret
2021-08-27 21:28:00 +02:00
func ( token * Token ) SignToken ( signingKey JWTSigningKey ) ( string , error ) {
2022-01-20 21:52:56 +00:00
token . IssuedAt = jwt . NewNumericDate ( time . Now ( ) )
2021-08-27 21:28:00 +02:00
jwtToken := jwt . NewWithClaims ( signingKey . SigningMethod ( ) , token )
signingKey . PreProcessToken ( jwtToken )
return jwtToken . SignedString ( signingKey . SignKey ( ) )
2021-07-24 11:16:34 +01:00
}
// OIDCToken represents an OpenID Connect id_token
type OIDCToken struct {
2022-01-20 21:52:56 +00:00
jwt . RegisteredClaims
2021-07-24 11:16:34 +01:00
Nonce string ` json:"nonce,omitempty" `
// Scope profile
Name string ` json:"name,omitempty" `
PreferredUsername string ` json:"preferred_username,omitempty" `
Profile string ` json:"profile,omitempty" `
Picture string ` json:"picture,omitempty" `
Website string ` json:"website,omitempty" `
Locale string ` json:"locale,omitempty" `
UpdatedAt timeutil . TimeStamp ` json:"updated_at,omitempty" `
// Scope email
Email string ` json:"email,omitempty" `
EmailVerified bool ` json:"email_verified,omitempty" `
2021-10-22 11:19:24 +02:00
// Groups are generated by organization and team names
Groups [ ] string ` json:"groups,omitempty" `
2021-07-24 11:16:34 +01:00
}
// SignToken signs an id_token with the (symmetric) client secret key
func ( token * OIDCToken ) SignToken ( signingKey JWTSigningKey ) ( string , error ) {
2022-01-20 21:52:56 +00:00
token . IssuedAt = jwt . NewNumericDate ( time . Now ( ) )
2021-07-24 11:16:34 +01:00
jwtToken := jwt . NewWithClaims ( signingKey . SigningMethod ( ) , token )
signingKey . PreProcessToken ( jwtToken )
return jwtToken . SignedString ( signingKey . SignKey ( ) )
}