New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `Validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
2022-08-27 13:07:09 +03:00
|
|
|
package jwt
|
|
|
|
|
|
|
|
import "time"
|
|
|
|
|
|
|
|
// ValidatorOption is used to implement functional-style options that modify the
|
|
|
|
// behavior of the validator. To add new options, just create a function
|
|
|
|
// (ideally beginning with With or Without) that returns an anonymous function
|
|
|
|
// that takes a *Parser type as input and manipulates its configuration
|
|
|
|
// accordingly.
|
|
|
|
type ValidatorOption func(*Validator)
|
|
|
|
|
2022-08-27 14:36:45 +03:00
|
|
|
// WithLeeway returns the ValidatorOption for specifying the leeway window.
|
New Validation API
Some guidelines in designing the new validation API
* Previously, the `Valid` method was placed on the claim, which was always not entirely semantically correct, since the validity is concerning the token, not the claims. Although the validity of the token is based on the processing of the claims (such as `exp`). Therefore, the function `Valid` was removed from the `Claims` interface and the single canonical way to retrieve the validity of the token is to retrieve the `Valid` property of the `Token` struct.
* The previous fact was enhanced by the fact that most claims implementations had additional exported `VerifyXXX` functions, which are now removed
* All validation errors should be comparable with `errors.Is` to determine, why a particular validation has failed
* Developers want to adjust validation options. Popular options include:
* Leeway when processing exp, nbf, iat
* Not verifying `iat`, since this is actually just an informational claim. When purely looking at the standard, this should probably the default
* Verifying `aud` by default, which actually the standard sort of demands. We need to see how strong we want to enforce this
* Developers want to create their own claim types, mostly by embedding one of the existing types such as `RegisteredClaims`.
* Sometimes there is the need to further tweak the validation of a token by checking the value of a custom claim. Previously, this was possibly by overriding `Valid`. However, this was error-prone, e.g., if the original `Valid` was not called. Therefore, we should provide an easy way for *additional* checks, without by-passing the necessary validations
This leads to the following two major changes:
* The `Claims` interface now represents a set of functions that return the mandatory claims represented in a token, rather than just a `Valid` function. This is also more semantically correct.
* All validation tasks are offloaded to a new (optional) `Validator`, which can also be configured with appropriate options. If no custom validator was supplied, a default one is used.
2022-08-27 13:07:09 +03:00
|
|
|
func WithLeeway(leeway time.Duration) ValidatorOption {
|
|
|
|
return func(v *Validator) {
|
|
|
|
v.leeway = leeway
|
|
|
|
}
|
|
|
|
}
|
2022-08-27 14:36:45 +03:00
|
|
|
|
|
|
|
// WithTimeFunc returns the ValidatorOption for specifying the time func. The
|
|
|
|
// primary use-case for this is testing. If you are looking for a way to account
|
|
|
|
// for clock-skew, WithLeeway should be used instead.
|
|
|
|
func WithTimeFunc(f func() time.Time) ValidatorOption {
|
|
|
|
return func(v *Validator) {
|
|
|
|
v.timeFunc = f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-27 14:42:01 +03:00
|
|
|
// WithIssuedAt returns the ValidatorOption to enable verification
|
2022-08-27 14:36:45 +03:00
|
|
|
// of issued-at.
|
2022-08-27 14:42:01 +03:00
|
|
|
func WithIssuedAt() ValidatorOption {
|
2022-08-27 14:36:45 +03:00
|
|
|
return func(v *Validator) {
|
|
|
|
v.verifyIat = true
|
|
|
|
}
|
|
|
|
}
|
2022-08-27 14:42:01 +03:00
|
|
|
|
2022-10-26 23:05:32 +03:00
|
|
|
// WithAudience configures the validator to require the specified audience in
|
|
|
|
// the `aud` claim. Validation will fail if the audience is not listed in the
|
|
|
|
// token or the `aud` claim is missing.
|
|
|
|
//
|
|
|
|
// NOTE: While the `aud` claim is OPTIONAL is a JWT, the handling of it is
|
|
|
|
// application-specific. Since this validation API is helping developers in
|
|
|
|
// writing secure application, we decided to REQUIRE the existence of the claim.
|
2022-08-27 14:42:01 +03:00
|
|
|
func WithAudience(aud string) ValidatorOption {
|
|
|
|
return func(v *Validator) {
|
|
|
|
v.expectedAud = aud
|
|
|
|
}
|
|
|
|
}
|
2022-10-26 23:05:32 +03:00
|
|
|
|
|
|
|
// WithIssuer configures the validator to require the specified issuer in the
|
|
|
|
// `iss` claim. Validation will fail if a different issuer is specified in the
|
|
|
|
// token or the `iss` claim is missing.
|
|
|
|
//
|
|
|
|
// NOTE: While the `iss` claim is OPTIONAL is a JWT, the handling of it is
|
|
|
|
// application-specific. Since this validation API is helping developers in
|
|
|
|
// writing secure application, we decided to REQUIRE the existence of the claim.
|
|
|
|
func WithIssuer(iss string) ValidatorOption {
|
|
|
|
return func(v *Validator) {
|
|
|
|
v.expectedIss = iss
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithSubject configures the validator to require the specified subject in the
|
|
|
|
// `sub` claim. Validation will fail if a different subject is specified in the
|
|
|
|
// token or the `sub` claim is missing.
|
|
|
|
//
|
|
|
|
// NOTE: While the `sub` claim is OPTIONAL is a JWT, the handling of it is
|
|
|
|
// application-specific. Since this validation API is helping developers in
|
|
|
|
// writing secure application, we decided to REQUIRE the existence of the claim.
|
|
|
|
func WithSubject(sub string) ValidatorOption {
|
|
|
|
return func(v *Validator) {
|
|
|
|
v.expectedSub = sub
|
|
|
|
}
|
|
|
|
}
|