1 package jwt
2 3 import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "strings"
8 )
9 10 const tokenDelimiter = "."
11 12 type Parser struct {
13 // If populated, only these methods will be considered valid.
14 //
15 // Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
16 ValidMethods []string
17 18 // Use JSON Number format in JSON decoder.
19 //
20 // Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
21 UseJSONNumber bool
22 23 // Skip claims validation during token parsing.
24 //
25 // Deprecated: In future releases, this field will not be exported anymore and should be set with an option to NewParser instead.
26 SkipClaimsValidation bool
27 }
28 29 // NewParser creates a new Parser with the specified options
30 func NewParser(options ...ParserOption) *Parser {
31 p := &Parser{}
32 33 // loop through our parsing options and apply them
34 for _, option := range options {
35 option(p)
36 }
37 38 return p
39 }
40 41 // Parse parses, validates, verifies the signature and returns the parsed token. keyFunc will
42 // receive the parsed token and should return the key for validating.
43 func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
44 return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
45 }
46 47 // ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object
48 // implementing the Claims interface. This provides default values which can be overridden and
49 // allows a caller to use their own type, rather than the default MapClaims implementation of
50 // Claims.
51 //
52 // Note: If you provide a custom claim implementation that embeds one of the standard claims (such
53 // as RegisteredClaims), make sure that a) you either embed a non-pointer version of the claims or
54 // b) if you are using a pointer, allocate the proper memory for it before passing in the overall
55 // claims, otherwise you might run into a panic.
56 func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
57 token, parts, err := p.ParseUnverified(tokenString, claims)
58 if err != nil {
59 return token, err
60 }
61 62 // Verify signing method is in the required set
63 if p.ValidMethods != nil {
64 var signingMethodValid = false
65 var alg = token.Method.Alg()
66 for _, m := range p.ValidMethods {
67 if m == alg {
68 signingMethodValid = true
69 break
70 }
71 }
72 if !signingMethodValid {
73 // signing method is not in the listed set
74 return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
75 }
76 }
77 78 // Lookup key
79 var key interface{}
80 if keyFunc == nil {
81 // keyFunc was not provided. short circuiting validation
82 return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
83 }
84 if key, err = keyFunc(token); err != nil {
85 // keyFunc returned an error
86 if ve, ok := err.(*ValidationError); ok {
87 return token, ve
88 }
89 return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
90 }
91 92 // Perform validation
93 token.Signature = parts[2]
94 if err := token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
95 return token, &ValidationError{Inner: err, Errors: ValidationErrorSignatureInvalid}
96 }
97 98 vErr := &ValidationError{}
99 100 // Validate Claims
101 if !p.SkipClaimsValidation {
102 if err := token.Claims.Valid(); err != nil {
103 // If the Claims Valid returned an error, check if it is a validation error,
104 // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
105 if e, ok := err.(*ValidationError); !ok {
106 vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
107 } else {
108 vErr = e
109 }
110 return token, vErr
111 }
112 }
113 114 // No errors so far, token is valid.
115 token.Valid = true
116 117 return token, nil
118 }
119 120 // ParseUnverified parses the token but doesn't validate the signature.
121 //
122 // WARNING: Don't use this method unless you know what you're doing.
123 //
124 // It's only ever useful in cases where you know the signature is valid (because it has
125 // been checked previously in the stack) and you want to extract values from it.
126 func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
127 var ok bool
128 parts, ok = splitToken(tokenString)
129 if !ok {
130 return nil, nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
131 }
132 133 token = &Token{Raw: tokenString}
134 135 // parse Header
136 var headerBytes []byte
137 if headerBytes, err = DecodeSegment(parts[0]); err != nil {
138 if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
139 return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
140 }
141 return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
142 }
143 if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
144 return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
145 }
146 147 // parse Claims
148 var claimBytes []byte
149 token.Claims = claims
150 151 if claimBytes, err = DecodeSegment(parts[1]); err != nil {
152 return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
153 }
154 dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
155 if p.UseJSONNumber {
156 dec.UseNumber()
157 }
158 // JSON Decode. Special case for map type to avoid weird pointer behavior
159 if c, ok := token.Claims.(MapClaims); ok {
160 err = dec.Decode(&c)
161 } else {
162 err = dec.Decode(&claims)
163 }
164 // Handle decode error
165 if err != nil {
166 return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
167 }
168 169 // Lookup signature method
170 if method, ok := token.Header["alg"].(string); ok {
171 if token.Method = GetSigningMethod(method); token.Method == nil {
172 return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
173 }
174 } else {
175 return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
176 }
177 178 return token, parts, nil
179 }
180 181 // splitToken splits a token string into three parts: header, claims, and signature. It will only
182 // return true if the token contains exactly two delimiters and three parts. In all other cases, it
183 // will return nil parts and false.
184 func splitToken(token string) ([]string, bool) {
185 parts := make([]string, 3)
186 header, remain, ok := strings.Cut(token, tokenDelimiter)
187 if !ok {
188 return nil, false
189 }
190 parts[0] = header
191 claims, remain, ok := strings.Cut(remain, tokenDelimiter)
192 if !ok {
193 return nil, false
194 }
195 parts[1] = claims
196 // One more cut to ensure the signature is the last part of the token and there are no more
197 // delimiters. This avoids an issue where malicious input could contain additional delimiters
198 // causing unecessary overhead parsing tokens.
199 signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
200 if unexpected {
201 return nil, false
202 }
203 parts[2] = signature
204 205 return parts, true
206 }
207