1 package jwt 2 3 import ( 4 "context" 5 "net/http" 6 "time" 7 8 "github.com/lestrrat-go/backoff/v2" 9 "github.com/lestrrat-go/jwx/jwa" 10 "github.com/lestrrat-go/jwx/jwe" 11 "github.com/lestrrat-go/jwx/jwk" 12 "github.com/lestrrat-go/jwx/jws" 13 "github.com/lestrrat-go/option" 14 ) 15 16 type Option = option.Interface 17 18 // GlobalOption describes an Option that can be passed to `Settings()`. 19 type GlobalOption interface { 20 Option 21 globalOption() 22 } 23 24 type globalOption struct { 25 Option 26 } 27 28 func (*globalOption) globalOption() {} 29 30 // ParseRequestOption describes an Option that can be passed to `ParseRequest()`. 31 type ParseRequestOption interface { 32 ParseOption 33 httpParseOption() 34 } 35 36 type httpParseOption struct { 37 ParseOption 38 } 39 40 func (*httpParseOption) httpParseOption() {} 41 42 // ParseOption describes an Option that can be passed to `Parse()`. 43 // ParseOption also implements ReadFileOption, therefore it may be 44 // safely pass them to `jwt.ReadFile()` 45 type ParseOption interface { 46 ReadFileOption 47 parseOption() 48 } 49 50 type parseOption struct { 51 Option 52 } 53 54 func newParseOption(n interface{}, v interface{}) ParseOption { 55 return &parseOption{option.New(n, v)} 56 } 57 58 func (*parseOption) parseOption() {} 59 func (*parseOption) readFileOption() {} 60 61 // SignOption describes an Option that can be passed to Sign() or 62 // (jwt.Serializer).Sign 63 type SignOption interface { 64 Option 65 signOption() 66 } 67 68 type signOption struct { 69 Option 70 } 71 72 func newSignOption(n interface{}, v interface{}) SignOption { 73 return &signOption{option.New(n, v)} 74 } 75 76 func (*signOption) signOption() {} 77 78 // EncryptOption describes an Option that can be passed to Encrypt() or 79 // (jwt.Serializer).Encrypt 80 type EncryptOption interface { 81 Option 82 encryptOption() 83 } 84 85 type encryptOption struct { 86 Option 87 } 88 89 func newEncryptOption(n interface{}, v interface{}) EncryptOption { 90 return &encryptOption{option.New(n, v)} 91 } 92 93 func (*encryptOption) encryptOption() {} 94 95 // ValidateOption describes an Option that can be passed to Validate(). 96 // ValidateOption also implements ParseOption, therefore it may be 97 // safely passed to `Parse()` (and thus `jwt.ReadFile()`) 98 type ValidateOption interface { 99 ParseOption 100 validateOption() 101 } 102 103 type validateOption struct { 104 ParseOption 105 } 106 107 func newValidateOption(n interface{}, v interface{}) ValidateOption { 108 return &validateOption{newParseOption(n, v)} 109 } 110 111 func (*validateOption) validateOption() {} 112 113 type identAcceptableSkew struct{} 114 type identClock struct{} 115 type identContext struct{} 116 type identDecrypt struct{} 117 type identDefault struct{} 118 type identFlattenAudience struct{} 119 type identInferAlgorithmFromKey struct{} 120 type identJweHeaders struct{} 121 type identJwsHeaders struct{} 122 type identKeySet struct{} 123 type identKeySetProvider struct{} 124 type identPedantic struct{} 125 type identValidator struct{} 126 type identToken struct{} 127 type identTypedClaim struct{} 128 type identValidate struct{} 129 type identVerify struct{} 130 type identVerifyAuto struct{} 131 type identFetchBackoff struct{} 132 type identFetchWhitelist struct{} 133 type identHTTPClient struct{} 134 type identJWKSetFetcher struct{} 135 136 type identHeaderKey struct{} 137 type identFormKey struct{} 138 139 type VerifyParameters interface { 140 Algorithm() jwa.SignatureAlgorithm 141 Key() interface{} 142 } 143 144 type verifyParams struct { 145 alg jwa.SignatureAlgorithm 146 key interface{} 147 } 148 149 func (p *verifyParams) Algorithm() jwa.SignatureAlgorithm { 150 return p.alg 151 } 152 153 func (p *verifyParams) Key() interface{} { 154 return p.key 155 } 156 157 // WithVerify forces the Parse method to verify the JWT message 158 // using the given key. XXX Should have been named something like 159 // WithVerificationKey 160 func WithVerify(alg jwa.SignatureAlgorithm, key interface{}) ParseOption { 161 return newParseOption(identVerify{}, &verifyParams{ 162 alg: alg, 163 key: key, 164 }) 165 } 166 167 // WithKeySet forces the Parse method to verify the JWT message 168 // using one of the keys in the given key set. 169 // 170 // The key and the JWT MUST have a proper `kid` field set. 171 // The key to use for signature verification is chosen by matching 172 // the Key ID of the JWT and the ID of the given key set. 173 // 174 // When using this option, keys MUST have a proper 'alg' field 175 // set. This is because we need to know the exact algorithm that 176 // you (the user) wants to use to verify the token. We do NOT 177 // trust the token's headers, because they can easily be tampered with. 178 // 179 // However, there _is_ a workaround if you do understand the risks 180 // of allowing a library to automatically choose a signature verification strategy, 181 // and you do not mind the verification process having to possibly 182 // attempt using multiple times before succeeding to verify. See 183 // `jwt.InferAlgorithmFromKey` option 184 // 185 // If you have only one key in the set, and are sure you want to 186 // use that key, you can use the `jwt.WithDefaultKey` option. 187 // 188 // If provided with WithKeySetProvider(), this option takes precedence. 189 func WithKeySet(set jwk.Set) ParseOption { 190 return newParseOption(identKeySet{}, set) 191 } 192 193 // UseDefaultKey is used in conjunction with the option WithKeySet 194 // to instruct the Parse method to default to the single key in a key 195 // set when no Key ID is included in the JWT. If the key set contains 196 // multiple keys then the default behavior is unchanged -- that is, 197 // the since we can't determine the key to use, it returns an error. 198 func UseDefaultKey(value bool) ParseOption { 199 return newParseOption(identDefault{}, value) 200 } 201 202 // WithToken specifies the token instance that is used when parsing 203 // JWT tokens. 204 func WithToken(t Token) ParseOption { 205 return newParseOption(identToken{}, t) 206 } 207 208 // WithHeaders is passed to `jwt.Sign()` function, to allow specifying arbitrary 209 // header values to be included in the header section of the jws message 210 // 211 // This option will be deprecated in the next major version. Use 212 // jwt.WithJwsHeaders() instead. 213 func WithHeaders(hdrs jws.Headers) SignOption { 214 return WithJwsHeaders(hdrs) 215 } 216 217 // WithJwsHeaders is passed to `jwt.Sign()` function or 218 // "jwt.Serializer".Sign() method, to allow specifying arbitrary 219 // header values to be included in the header section of the JWE message 220 func WithJwsHeaders(hdrs jws.Headers) SignOption { 221 return newSignOption(identJwsHeaders{}, hdrs) 222 } 223 224 // WithJweHeaders is passed to "jwt.Serializer".Encrypt() method to allow 225 // specifying arbitrary header values to be included in the protected header 226 // of the JWE message 227 func WithJweHeaders(hdrs jwe.Headers) EncryptOption { 228 return newEncryptOption(identJweHeaders{}, hdrs) 229 } 230 231 // WithValidate is passed to `Parse()` method to denote that the 232 // validation of the JWT token should be performed after a successful 233 // parsing of the incoming payload. 234 func WithValidate(b bool) ParseOption { 235 return newParseOption(identValidate{}, b) 236 } 237 238 // WithClock specifies the `Clock` to be used when verifying 239 // claims exp and nbf. 240 func WithClock(c Clock) ValidateOption { 241 return newValidateOption(identClock{}, c) 242 } 243 244 // WithAcceptableSkew specifies the duration in which exp and nbf 245 // claims may differ by. This value should be positive 246 func WithAcceptableSkew(dur time.Duration) ValidateOption { 247 return newValidateOption(identAcceptableSkew{}, dur) 248 } 249 250 // WithIssuer specifies that expected issuer value. If not specified, 251 // the value of issuer is not verified at all. 252 func WithIssuer(s string) ValidateOption { 253 return WithValidator(ClaimValueIs(IssuerKey, s)) 254 } 255 256 // WithSubject specifies that expected subject value. If not specified, 257 // the value of subject is not verified at all. 258 func WithSubject(s string) ValidateOption { 259 return WithValidator(ClaimValueIs(SubjectKey, s)) 260 } 261 262 // WithJwtID specifies that expected jti value. If not specified, 263 // the value of jti is not verified at all. 264 func WithJwtID(s string) ValidateOption { 265 return WithValidator(ClaimValueIs(JwtIDKey, s)) 266 } 267 268 // WithAudience specifies that expected audience value. 269 // `Validate()` will return true if one of the values in the `aud` element 270 // matches this value. If not specified, the value of issuer is not 271 // verified at all. 272 func WithAudience(s string) ValidateOption { 273 return WithValidator(ClaimContainsString(AudienceKey, s)) 274 } 275 276 // WithClaimValue specifies the expected value for a given claim 277 func WithClaimValue(name string, v interface{}) ValidateOption { 278 return WithValidator(ClaimValueIs(name, v)) 279 } 280 281 // WithHeaderKey is used to specify header keys to search for tokens. 282 // 283 // While the type system allows this option to be passed to jwt.Parse() directly, 284 // doing so will have no effect. Only use it for HTTP request parsing functions 285 func WithHeaderKey(v string) ParseRequestOption { 286 return &httpParseOption{newParseOption(identHeaderKey{}, v)} 287 } 288 289 // WithFormKey is used to specify header keys to search for tokens. 290 // 291 // While the type system allows this option to be passed to jwt.Parse() directly, 292 // doing so will have no effect. Only use it for HTTP request parsing functions 293 func WithFormKey(v string) ParseRequestOption { 294 return &httpParseOption{newParseOption(identFormKey{}, v)} 295 } 296 297 // WithFlattenAudience specifies if the "aud" claim should be flattened 298 // to a single string upon the token being serialized to JSON. 299 // 300 // This is sometimes important when a JWT consumer does not understand that 301 // the "aud" claim can actually take the form of an array of strings. 302 // 303 // The default value is `false`, which means that "aud" claims are always 304 // rendered as a arrays of strings. This setting has a global effect, 305 // and will change the behavior for all JWT serialization. 306 func WithFlattenAudience(v bool) GlobalOption { 307 return &globalOption{option.New(identFlattenAudience{}, v)} 308 } 309 310 type claimPair struct { 311 Name string 312 Value interface{} 313 } 314 315 // WithTypedClaim allows a private claim to be parsed into the object type of 316 // your choice. It works much like the RegisterCustomField, but the effect 317 // is only applicable to the jwt.Parse function call which receives this option. 318 // 319 // While this can be extremely useful, this option should be used with caution: 320 // There are many caveats that your entire team/user-base needs to be aware of, 321 // and therefore in general its use is discouraged. Only use it when you know 322 // what you are doing, and you document its use clearly for others. 323 // 324 // First and foremost, this is a "per-object" option. Meaning that given the same 325 // serialized format, it is possible to generate two objects whose internal 326 // representations may differ. That is, if you parse one _WITH_ the option, 327 // and the other _WITHOUT_, their internal representation may completely differ. 328 // This could potentially lead to problems. 329 // 330 // Second, specifying this option will slightly slow down the decoding process 331 // as it needs to consult multiple definitions sources (global and local), so 332 // be careful if you are decoding a large number of tokens, as the effects will stack up. 333 // 334 // Finally, this option will also NOT work unless the tokens themselves support such 335 // parsing mechanism. For example, while tokens obtained from `jwt.New()` and 336 // `openid.New()` will respect this option, if you provide your own custom 337 // token type, it will need to implement the TokenWithDecodeCtx interface. 338 func WithTypedClaim(name string, object interface{}) ParseOption { 339 return newParseOption(identTypedClaim{}, claimPair{Name: name, Value: object}) 340 } 341 342 // WithRequiredClaim specifies that the claim identified the given name 343 // must exist in the token. Only the existence of the claim is checked: 344 // the actual value associated with that field is not checked. 345 func WithRequiredClaim(name string) ValidateOption { 346 return WithValidator(IsRequired(name)) 347 } 348 349 // WithMaxDelta specifies that given two claims `c1` and `c2` that represent time, the difference in 350 // time.Duration must be less than equal to the value specified by `d`. If `c1` or `c2` is the 351 // empty string, the current time (as computed by `time.Now` or the object passed via 352 // `WithClock()`) is used for the comparison. 353 // 354 // `c1` and `c2` are also assumed to be required, therefore not providing either claim in the 355 // token will result in an error. 356 // 357 // Because there is no way of reliably knowing how to parse private claims, we currently only 358 // support `iat`, `exp`, and `nbf` claims. 359 // 360 // If the empty string is passed to c1 or c2, then the current time (as calculated by time.Now() or 361 // the clock object provided via WithClock()) is used. 362 // 363 // For example, in order to specify that `exp` - `iat` should be less than 10*time.Second, you would write 364 // 365 // jwt.Validate(token, jwt.WithMaxDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) 366 // 367 // If AcceptableSkew of 2 second is specified, the above will return valid for any value of 368 // `exp` - `iat` between 8 (10-2) and 12 (10+2). 369 func WithMaxDelta(dur time.Duration, c1, c2 string) ValidateOption { 370 return WithValidator(MaxDeltaIs(c1, c2, dur)) 371 } 372 373 // WithMinDelta is almost exactly the same as WithMaxDelta, but force validation to fail if 374 // the difference between time claims are less than dur. 375 // 376 // For example, in order to specify that `exp` - `iat` should be greater than 10*time.Second, you would write 377 // 378 // jwt.Validate(token, jwt.WithMinDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey)) 379 // 380 // The validation would fail if the difference is less than 10 seconds. 381 // 382 func WithMinDelta(dur time.Duration, c1, c2 string) ValidateOption { 383 return WithValidator(MinDeltaIs(c1, c2, dur)) 384 } 385 386 // WithValidator validates the token with the given Validator. 387 // 388 // For example, in order to validate tokens that are only valid during August, you would write 389 // 390 // validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error { 391 // if time.Now().Month() != 8 { 392 // return fmt.Errorf(`tokens are only valid during August!`) 393 // } 394 // return nil 395 // }) 396 // err := jwt.Validate(token, jwt.WithValidator(validator)) 397 // 398 func WithValidator(v Validator) ValidateOption { 399 return newValidateOption(identValidator{}, v) 400 } 401 402 type decryptParams struct { 403 alg jwa.KeyEncryptionAlgorithm 404 key interface{} 405 } 406 407 type DecryptParameters interface { 408 Algorithm() jwa.KeyEncryptionAlgorithm 409 Key() interface{} 410 } 411 412 func (dp *decryptParams) Algorithm() jwa.KeyEncryptionAlgorithm { 413 return dp.alg 414 } 415 416 func (dp *decryptParams) Key() interface{} { 417 return dp.key 418 } 419 420 // WithDecrypt allows users to specify parameters for decryption using 421 // `jwe.Decrypt`. You must specify this if your JWT is encrypted. 422 func WithDecrypt(alg jwa.KeyEncryptionAlgorithm, key interface{}) ParseOption { 423 return newParseOption(identDecrypt{}, &decryptParams{ 424 alg: alg, 425 key: key, 426 }) 427 } 428 429 // WithPedantic enables pedantic mode for parsing JWTs. Currently this only 430 // applies to checking for the correct `typ` and/or `cty` when necessary. 431 func WithPedantic(v bool) ParseOption { 432 return newParseOption(identPedantic{}, v) 433 } 434 435 // InferAlgorithmFromKey allows jwt.Parse to guess the signature algorithm 436 // passed to `jws.Verify()`, in case the key you provided does not have a proper `alg` header. 437 // 438 // Compared to providing explicit `alg` from the key this is slower, and in 439 // case our heuristics are wrong or outdated, may fail to verify the token. 440 // Also, automatic detection of signature verification methods are always 441 // more vulnerable for potential attack vectors. 442 // 443 // It is highly recommended that you fix your key to contain a proper `alg` 444 // header field instead of resorting to using this option, but sometimes 445 // it just needs to happen. 446 // 447 // Your JWT still need to have an `alg` field, and it must match one of the 448 // candidates that we produce for your key 449 func InferAlgorithmFromKey(v bool) ParseOption { 450 return newParseOption(identInferAlgorithmFromKey{}, v) 451 } 452 453 // KeySetProvider is an interface for objects that can choose the appropriate 454 // jwk.Set to be used when verifying JWTs 455 type KeySetProvider interface { 456 // KeySetFrom returns the jwk.Set to be used to verify the token. 457 // Keep in mind that the token at the point when the method is called is NOT VERIFIED. 458 // DO NOT trust the contents of the Token too much. For example, do not take the 459 // hint as to which signature algorithm to use from the token itself. 460 KeySetFrom(Token) (jwk.Set, error) 461 } 462 463 // KeySetProviderFunc is an implementation of KeySetProvider that is based 464 // on a function. 465 type KeySetProviderFunc func(Token) (jwk.Set, error) 466 467 func (fn KeySetProviderFunc) KeySetFrom(t Token) (jwk.Set, error) { 468 return fn(t) 469 } 470 471 // WithKeySetProvider allows users to specify an object to choose which 472 // jwk.Set to use for verification. 473 // 474 // If provided with WithKeySet(), WithKeySet() option takes precedence. 475 func WithKeySetProvider(p KeySetProvider) ParseOption { 476 return newParseOption(identKeySetProvider{}, p) 477 } 478 479 // WithContext allows you to specify a context.Context object to be used 480 // with `jwt.Validate()` option. 481 // 482 // Please be aware that in the next major release of this library, 483 // `jwt.Validate()`'s signature will change to include an explicit 484 // `context.Context` object. 485 func WithContext(ctx context.Context) ValidateOption { 486 return newValidateOption(identContext{}, ctx) 487 } 488 489 // WithVerifyAuto specifies that the JWS verification should be performed 490 // using `jws.VerifyAuto()`, which in turn attempts to verify the message 491 // using values that are stored within the JWS message. 492 // 493 // Only passing this option to `jwt.Parse()` will not result in a successful 494 // verification. Please make sure to carefully read the documentation in 495 // `jws.VerifyAuto()`, and provide the necessary Whitelist object via 496 // `jwt.WithFetchWhitelist()` 497 // 498 // You might also consider using a backoff policy by using `jwt.WithFetchBackoff()` 499 // to control the number of requests being made. 500 func WithVerifyAuto(v bool) ParseOption { 501 return newParseOption(identVerifyAuto{}, v) 502 } 503 504 // WithFetchWhitelist specifies the `jwk.Whitelist` object that should be 505 // passed to `jws.VerifyAuto()`, which in turn will be passed to `jwk.Fetch()` 506 // 507 // This is a wrapper over `jws.WithFetchWhitelist()` that can be passed 508 // to `jwt.Parse()`, and will be ignored if you spcify `jws.WithJWKSetFetcher()` 509 func WithFetchWhitelist(wl jwk.Whitelist) ParseOption { 510 return newParseOption(identFetchWhitelist{}, wl) 511 } 512 513 // WithHTTPClient specifies the `*http.Client` object that should be 514 // passed to `jws.VerifyAuto()`, which in turn will be passed to `jwk.Fetch()` 515 // 516 // This is a wrapper over `jws.WithHTTPClient()` that can be passed 517 // to `jwt.Parse()`, and will be ignored if you spcify `jws.WithJWKSetFetcher()` 518 func WithHTTPClient(httpcl *http.Client) ParseOption { 519 return newParseOption(identHTTPClient{}, httpcl) 520 } 521 522 // WithFetchBackoff specifies the `backoff.Policy` object that should be 523 // passed to `jws.VerifyAuto()`, which in turn will be passed to `jwk.Fetch()` 524 // 525 // This is a wrapper over `jws.WithFetchBackoff()` that can be passed 526 // to `jwt.Parse()`, and will be ignored if you spcify `jws.WithJWKSetFetcher()` 527 func WithFetchBackoff(b backoff.Policy) ParseOption { 528 return newParseOption(identFetchBackoff{}, b) 529 } 530 531 // WithJWKSetFetcher specifies the `jws.JWKSetFetcher` object that should be 532 // passed to `jws.VerifyAuto()` 533 // 534 // This is a wrapper over `jws.WithJWKSetFetcher()` that can be passed 535 // to `jwt.Parse()`. 536 func WithJWKSetFetcher(f jws.JWKSetFetcher) ParseOption { 537 return newParseOption(identJWKSetFetcher{}, f) 538 } 539