1package jwt
2
3import (
4 "bytes"
5 "encoding/base64"
6 "encoding/json"
7 "fmt"
8 "strings"
9)
10
11const tokenDelimiter = "."
12
13type Parser struct {
14 // If populated, only these methods will be considered valid.
15 validMethods []string
16
17 // Use JSON Number format in JSON decoder.
18 useJSONNumber bool
19
20 // Skip claims validation during token parsing.
21 skipClaimsValidation bool
22
23 validator *Validator
24
25 decodeStrict bool
26
27 decodePaddingAllowed bool
28}
29
30// NewParser creates a new Parser with the specified options
31func NewParser(options ...ParserOption) *Parser {
32 p := &Parser{
33 validator: &Validator{},
34 }
35
36 // Loop through our parsing options and apply them
37 for _, option := range options {
38 option(p)
39 }
40
41 return p
42}
43
44// Parse parses, validates, verifies the signature and returns the parsed token.
45// keyFunc will receive the parsed token and should return the key for validating.
46func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
47 return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
48}
49
50// ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims
51// interface. This provides default values which can be overridden and allows a caller to use their own type, rather
52// than the default MapClaims implementation of Claims.
53//
54// Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
55// make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
56// proper memory for it before passing in the overall claims, otherwise you might run into a panic.
57func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
58 token, parts, err := p.ParseUnverified(tokenString, claims)
59 if err != nil {
60 return token, err
61 }
62
63 // Verify signing method is in the required set
64 if p.validMethods != nil {
65 var signingMethodValid = false
66 var alg = token.Method.Alg()
67 for _, m := range p.validMethods {
68 if m == alg {
69 signingMethodValid = true
70 break
71 }
72 }
73 if !signingMethodValid {
74 // signing method is not in the listed set
75 return token, newError(fmt.Sprintf("signing method %v is invalid", alg), ErrTokenSignatureInvalid)
76 }
77 }
78
79 // Decode signature
80 token.Signature, err = p.DecodeSegment(parts[2])
81 if err != nil {
82 return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
83 }
84 text := strings.Join(parts[0:2], ".")
85
86 // Lookup key(s)
87 if keyFunc == nil {
88 // keyFunc was not provided. short circuiting validation
89 return token, newError("no keyfunc was provided", ErrTokenUnverifiable)
90 }
91
92 got, err := keyFunc(token)
93 if err != nil {
94 return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
95 }
96
97 switch have := got.(type) {
98 case VerificationKeySet:
99 if len(have.Keys) == 0 {
100 return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
101 }
102 // Iterate through keys and verify signature, skipping the rest when a match is found.
103 // Return the last error if no match is found.
104 for _, key := range have.Keys {
105 if err = token.Method.Verify(text, token.Signature, key); err == nil {
106 break
107 }
108 }
109 default:
110 err = token.Method.Verify(text, token.Signature, have)
111 }
112 if err != nil {
113 return token, newError("", ErrTokenSignatureInvalid, err)
114 }
115
116 // Validate Claims
117 if !p.skipClaimsValidation {
118 // Make sure we have at least a default validator
119 if p.validator == nil {
120 p.validator = NewValidator()
121 }
122
123 if err := p.validator.Validate(claims); err != nil {
124 return token, newError("", ErrTokenInvalidClaims, err)
125 }
126 }
127
128 // No errors so far, token is valid.
129 token.Valid = true
130
131 return token, nil
132}
133
134// ParseUnverified parses the token but doesn't validate the signature.
135//
136// WARNING: Don't use this method unless you know what you're doing.
137//
138// It's only ever useful in cases where you know the signature is valid (since it has already
139// been or will be checked elsewhere in the stack) and you want to extract values from it.
140func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
141 var ok bool
142 parts, ok = splitToken(tokenString)
143 if !ok {
144 return nil, nil, newError("token contains an invalid number of segments", ErrTokenMalformed)
145 }
146
147 token = &Token{Raw: tokenString}
148
149 // parse Header
150 var headerBytes []byte
151 if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
152 return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
153 }
154 if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
155 return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err)
156 }
157
158 // parse Claims
159 token.Claims = claims
160
161 claimBytes, err := p.DecodeSegment(parts[1])
162 if err != nil {
163 return token, parts, newError("could not base64 decode claim", ErrTokenMalformed, err)
164 }
165
166 // If `useJSONNumber` is enabled then we must use *json.Decoder to decode
167 // the claims. However, this comes with a performance penalty so only use
168 // it if we must and, otherwise, simple use json.Unmarshal.
169 if !p.useJSONNumber {
170 // JSON Unmarshal. Special case for map type to avoid weird pointer behavior.
171 if c, ok := token.Claims.(MapClaims); ok {
172 err = json.Unmarshal(claimBytes, &c)
173 } else {
174 err = json.Unmarshal(claimBytes, &claims)
175 }
176 } else {
177 dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
178 dec.UseNumber()
179 // JSON Decode. Special case for map type to avoid weird pointer behavior.
180 if c, ok := token.Claims.(MapClaims); ok {
181 err = dec.Decode(&c)
182 } else {
183 err = dec.Decode(&claims)
184 }
185 }
186 if err != nil {
187 return token, parts, newError("could not JSON decode claim", ErrTokenMalformed, err)
188 }
189
190 // Lookup signature method
191 if method, ok := token.Header["alg"].(string); ok {
192 if token.Method = GetSigningMethod(method); token.Method == nil {
193 return token, parts, newError("signing method (alg) is unavailable", ErrTokenUnverifiable)
194 }
195 } else {
196 return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable)
197 }
198
199 return token, parts, nil
200}
201
202// splitToken splits a token string into three parts: header, claims, and signature. It will only
203// return true if the token contains exactly two delimiters and three parts. In all other cases, it
204// will return nil parts and false.
205func splitToken(token string) ([]string, bool) {
206 parts := make([]string, 3)
207 header, remain, ok := strings.Cut(token, tokenDelimiter)
208 if !ok {
209 return nil, false
210 }
211 parts[0] = header
212 claims, remain, ok := strings.Cut(remain, tokenDelimiter)
213 if !ok {
214 return nil, false
215 }
216 parts[1] = claims
217 // One more cut to ensure the signature is the last part of the token and there are no more
218 // delimiters. This avoids an issue where malicious input could contain additional delimiters
219 // causing unecessary overhead parsing tokens.
220 signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
221 if unexpected {
222 return nil, false
223 }
224 parts[2] = signature
225
226 return parts, true
227}
228
229// DecodeSegment decodes a JWT specific base64url encoding. This function will
230// take into account whether the [Parser] is configured with additional options,
231// such as [WithStrictDecoding] or [WithPaddingAllowed].
232func (p *Parser) DecodeSegment(seg string) ([]byte, error) {
233 encoding := base64.RawURLEncoding
234
235 if p.decodePaddingAllowed {
236 if l := len(seg) % 4; l > 0 {
237 seg += strings.Repeat("=", 4-l)
238 }
239 encoding = base64.URLEncoding
240 }
241
242 if p.decodeStrict {
243 encoding = encoding.Strict()
244 }
245 return encoding.DecodeString(seg)
246}
247
248// Parse parses, validates, verifies the signature and returns the parsed token.
249// keyFunc will receive the parsed token and should return the cryptographic key
250// for verifying the signature. The caller is strongly encouraged to set the
251// WithValidMethods option to validate the 'alg' claim in the token matches the
252// expected algorithm. For more details about the importance of validating the
253// 'alg' claim, see
254// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
255func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
256 return NewParser(options...).Parse(tokenString, keyFunc)
257}
258
259// ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
260//
261// Note: If you provide a custom claim implementation that embeds one of the
262// standard claims (such as RegisteredClaims), make sure that a) you either
263// embed a non-pointer version of the claims or b) if you are using a pointer,
264// allocate the proper memory for it before passing in the overall claims,
265// otherwise you might run into a panic.
266func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
267 return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
268}