-
Notifications
You must be signed in to change notification settings - Fork 32
/
tokenparser.go
88 lines (80 loc) · 2.51 KB
/
tokenparser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package auth
import (
"errors"
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
const leeway = 5 * time.Second
// TokenClaims represents access token claims
type TokenClaims struct {
Name string `json:"name"`
PreferredUsername string `json:"preferred_username"`
GivenName string `json:"given_name"`
FamilyName string `json:"family_name"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
Company string `json:"company"`
OriginalSub string `json:"original_sub"`
UserID string `json:"user_id"`
AccountID string `json:"account_id"`
jwt.RegisteredClaims
}
// TokenParser represents a parser for JWT tokens.
type TokenParser struct {
keyManager *KeyManager
}
// NewTokenParser creates a new TokenParser.
func NewTokenParser(keyManager *KeyManager) (*TokenParser, error) {
if keyManager == nil {
return nil, errors.New("no keyManager given when creating TokenParser")
}
return &TokenParser{
keyManager: keyManager,
}, nil
}
// FromString parses a JWT, validates the signature and returns the claims struct.
func (tp *TokenParser) FromString(jwtEncoded string) (*TokenClaims, error) {
token, err := jwt.ParseWithClaims(
jwtEncoded,
&TokenClaims{},
func(token *jwt.Token) (interface{}, error) {
// validate the alg is what we expect
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
kid := token.Header["kid"]
if kid == nil {
return nil, errors.New("no key id given in the token")
}
kidStr, ok := kid.(string)
if !ok {
return nil, errors.New("given key id has unknown type")
}
// get the public key for kid from keyManager
publicKey, err := tp.keyManager.Key(kidStr)
if err != nil {
return nil, err
}
return publicKey, nil
},
jwt.WithLeeway(leeway),
)
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*TokenClaims); ok && token.Valid {
// we need username and email, so check if those are contained in the claims
if claims.PreferredUsername == "" {
return nil, errors.New("token does not comply to expected claims: username missing")
}
if claims.Email == "" {
return nil, errors.New("token does not comply to expected claims: email missing")
}
if claims.Subject == "" {
return nil, errors.New("token does not comply to expected claims: subject missing")
}
return claims, nil
}
return nil, errors.New("token does not comply to expected claims")
}