summaryrefslogtreecommitdiffstats
path: root/services/auth/source/oauth2/token.go
diff options
context:
space:
mode:
Diffstat (limited to 'services/auth/source/oauth2/token.go')
-rw-r--r--services/auth/source/oauth2/token.go100
1 files changed, 100 insertions, 0 deletions
diff --git a/services/auth/source/oauth2/token.go b/services/auth/source/oauth2/token.go
new file mode 100644
index 0000000..3405619
--- /dev/null
+++ b/services/auth/source/oauth2/token.go
@@ -0,0 +1,100 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package oauth2
+
+import (
+ "fmt"
+ "time"
+
+ "code.gitea.io/gitea/modules/timeutil"
+
+ "github.com/golang-jwt/jwt/v5"
+)
+
+// ___________ __
+// \__ ___/___ | | __ ____ ____
+// | | / _ \| |/ // __ \ / \
+// | |( <_> ) <\ ___/| | \
+// |____| \____/|__|_ \\___ >___| /
+// \/ \/ \/
+
+// Token represents an Oauth grant
+
+// TokenType represents the type of token for an oauth application
+type TokenType int
+
+const (
+ // TypeAccessToken is a token with short lifetime to access the api
+ TypeAccessToken TokenType = 0
+ // TypeRefreshToken is token with long lifetime to refresh access tokens obtained by the client
+ TypeRefreshToken = iota
+)
+
+// Token represents a JWT token used to authenticate a client
+type Token struct {
+ GrantID int64 `json:"gnt"`
+ Type TokenType `json:"tt"`
+ Counter int64 `json:"cnt,omitempty"`
+ jwt.RegisteredClaims
+}
+
+// ParseToken parses a signed jwt string
+func ParseToken(jwtToken string, signingKey JWTSigningKey) (*Token, error) {
+ parsedToken, err := jwt.ParseWithClaims(jwtToken, &Token{}, func(token *jwt.Token) (any, error) {
+ if token.Method == nil || token.Method.Alg() != signingKey.SigningMethod().Alg() {
+ return nil, fmt.Errorf("unexpected signing algo: %v", token.Header["alg"])
+ }
+ return signingKey.VerifyKey(), nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ if !parsedToken.Valid {
+ return nil, fmt.Errorf("invalid token")
+ }
+ 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
+func (token *Token) SignToken(signingKey JWTSigningKey) (string, error) {
+ token.IssuedAt = jwt.NewNumericDate(time.Now())
+ jwtToken := jwt.NewWithClaims(signingKey.SigningMethod(), token)
+ signingKey.PreProcessToken(jwtToken)
+ return jwtToken.SignedString(signingKey.SignKey())
+}
+
+// OIDCToken represents an OpenID Connect id_token
+type OIDCToken struct {
+ jwt.RegisteredClaims
+ 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"`
+
+ // Groups are generated by organization and team names
+ Groups []string `json:"groups,omitempty"`
+}
+
+// SignToken signs an id_token with the (symmetric) client secret key
+func (token *OIDCToken) SignToken(signingKey JWTSigningKey) (string, error) {
+ token.IssuedAt = jwt.NewNumericDate(time.Now())
+ jwtToken := jwt.NewWithClaims(signingKey.SigningMethod(), token)
+ signingKey.PreProcessToken(jwtToken)
+ return jwtToken.SignedString(signingKey.SignKey())
+}