code.gitea.io/gitea@v1.21.7/services/auth/source/oauth2/token.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package oauth2
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"code.gitea.io/gitea/modules/timeutil"
    11  
    12  	"github.com/golang-jwt/jwt/v5"
    13  )
    14  
    15  // ___________     __
    16  // \__    ___/___ |  | __ ____   ____
    17  //   |    | /  _ \|  |/ // __ \ /    \
    18  //   |    |(  <_> )    <\  ___/|   |  \
    19  //   |____| \____/|__|_ \\___  >___|  /
    20  //                     \/    \/     \/
    21  
    22  // Token represents an Oauth grant
    23  
    24  // TokenType represents the type of token for an oauth application
    25  type TokenType int
    26  
    27  const (
    28  	// TypeAccessToken is a token with short lifetime to access the api
    29  	TypeAccessToken TokenType = 0
    30  	// TypeRefreshToken is token with long lifetime to refresh access tokens obtained by the client
    31  	TypeRefreshToken = iota
    32  )
    33  
    34  // Token represents a JWT token used to authenticate a client
    35  type Token struct {
    36  	GrantID int64     `json:"gnt"`
    37  	Type    TokenType `json:"tt"`
    38  	Counter int64     `json:"cnt,omitempty"`
    39  	jwt.RegisteredClaims
    40  }
    41  
    42  // ParseToken parses a signed jwt string
    43  func ParseToken(jwtToken string, signingKey JWTSigningKey) (*Token, error) {
    44  	parsedToken, err := jwt.ParseWithClaims(jwtToken, &Token{}, func(token *jwt.Token) (any, error) {
    45  		if token.Method == nil || token.Method.Alg() != signingKey.SigningMethod().Alg() {
    46  			return nil, fmt.Errorf("unexpected signing algo: %v", token.Header["alg"])
    47  		}
    48  		return signingKey.VerifyKey(), nil
    49  	})
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	if !parsedToken.Valid {
    54  		return nil, fmt.Errorf("invalid token")
    55  	}
    56  	var token *Token
    57  	var ok bool
    58  	if token, ok = parsedToken.Claims.(*Token); !ok || !parsedToken.Valid {
    59  		return nil, fmt.Errorf("invalid token")
    60  	}
    61  	return token, nil
    62  }
    63  
    64  // SignToken signs the token with the JWT secret
    65  func (token *Token) SignToken(signingKey JWTSigningKey) (string, error) {
    66  	token.IssuedAt = jwt.NewNumericDate(time.Now())
    67  	jwtToken := jwt.NewWithClaims(signingKey.SigningMethod(), token)
    68  	signingKey.PreProcessToken(jwtToken)
    69  	return jwtToken.SignedString(signingKey.SignKey())
    70  }
    71  
    72  // OIDCToken represents an OpenID Connect id_token
    73  type OIDCToken struct {
    74  	jwt.RegisteredClaims
    75  	Nonce string `json:"nonce,omitempty"`
    76  
    77  	// Scope profile
    78  	Name              string             `json:"name,omitempty"`
    79  	PreferredUsername string             `json:"preferred_username,omitempty"`
    80  	Profile           string             `json:"profile,omitempty"`
    81  	Picture           string             `json:"picture,omitempty"`
    82  	Website           string             `json:"website,omitempty"`
    83  	Locale            string             `json:"locale,omitempty"`
    84  	UpdatedAt         timeutil.TimeStamp `json:"updated_at,omitempty"`
    85  
    86  	// Scope email
    87  	Email         string `json:"email,omitempty"`
    88  	EmailVerified bool   `json:"email_verified,omitempty"`
    89  
    90  	// Groups are generated by organization and team names
    91  	Groups []string `json:"groups,omitempty"`
    92  }
    93  
    94  // SignToken signs an id_token with the (symmetric) client secret key
    95  func (token *OIDCToken) SignToken(signingKey JWTSigningKey) (string, error) {
    96  	token.IssuedAt = jwt.NewNumericDate(time.Now())
    97  	jwtToken := jwt.NewWithClaims(signingKey.SigningMethod(), token)
    98  	signingKey.PreProcessToken(jwtToken)
    99  	return jwtToken.SignedString(signingKey.SignKey())
   100  }