2015-04-09 23:20:10 +03:00
|
|
|
package jwt
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Error constants
|
|
|
|
var (
|
2016-06-07 20:34:06 +03:00
|
|
|
ErrInvalidKey = errors.New("key is invalid")
|
|
|
|
ErrInvalidKeyType = errors.New("key is of invalid type")
|
2016-04-08 23:58:29 +03:00
|
|
|
ErrHashUnavailable = errors.New("the requested hash function is unavailable")
|
2022-01-20 00:55:19 +03:00
|
|
|
|
|
|
|
ErrTokenMalformed = errors.New("token is malformed")
|
|
|
|
ErrTokenUnverifiable = errors.New("token is unverifiable")
|
|
|
|
ErrTokenSignatureInvalid = errors.New("token signature is invalid")
|
|
|
|
|
|
|
|
ErrTokenInvalidAudience = errors.New("token has invalid audience")
|
|
|
|
ErrTokenExpired = errors.New("token is expired")
|
|
|
|
ErrTokenUsedBeforeIssued = errors.New("token used before issued")
|
|
|
|
ErrTokenInvalidIssuer = errors.New("token has invalid issuer")
|
New validation API (#236)
* 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.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
ErrTokenInvalidSubject = errors.New("token has invalid subject")
|
2022-01-20 00:55:19 +03:00
|
|
|
ErrTokenNotValidYet = errors.New("token is not valid yet")
|
|
|
|
ErrTokenInvalidId = errors.New("token has invalid id")
|
|
|
|
ErrTokenInvalidClaims = errors.New("token has invalid claims")
|
2023-02-09 23:06:03 +03:00
|
|
|
|
|
|
|
ErrInvalidType = errors.New("invalid type for claim")
|
2015-04-09 23:20:10 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// The errors that might occur when parsing and validating a token
|
|
|
|
const (
|
|
|
|
ValidationErrorMalformed uint32 = 1 << iota // Token is malformed
|
|
|
|
ValidationErrorUnverifiable // Token could not be verified because of signing problems
|
|
|
|
ValidationErrorSignatureInvalid // Signature validation failed
|
2015-07-17 22:40:52 +03:00
|
|
|
|
New validation API (#236)
* 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.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
// Registered Claim validation errors
|
2015-07-17 22:40:52 +03:00
|
|
|
ValidationErrorAudience // AUD validation failed
|
|
|
|
ValidationErrorExpired // EXP validation failed
|
|
|
|
ValidationErrorIssuedAt // IAT validation failed
|
|
|
|
ValidationErrorIssuer // ISS validation failed
|
New validation API (#236)
* 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.
Co-authored-by: Micah Parks <66095735+MicahParks@users.noreply.github.com>
2022-12-05 16:56:21 +03:00
|
|
|
ValidationErrorSubject // SUB validation failed
|
2015-07-17 22:40:52 +03:00
|
|
|
ValidationErrorNotValidYet // NBF validation failed
|
|
|
|
ValidationErrorId // JTI validation failed
|
|
|
|
ValidationErrorClaimsInvalid // Generic claims validation error
|
2015-04-09 23:20:10 +03:00
|
|
|
)
|
|
|
|
|
2021-08-03 16:51:01 +03:00
|
|
|
// NewValidationError is a helper for constructing a ValidationError with a string error message
|
2016-04-13 03:31:30 +03:00
|
|
|
func NewValidationError(errorText string, errorFlags uint32) *ValidationError {
|
|
|
|
return &ValidationError{
|
2016-06-16 02:42:50 +03:00
|
|
|
text: errorText,
|
2016-04-13 03:31:30 +03:00
|
|
|
Errors: errorFlags,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-03 16:51:01 +03:00
|
|
|
// ValidationError represents an error from Parse if token is not valid
|
2015-04-09 23:20:10 +03:00
|
|
|
type ValidationError struct {
|
2023-02-09 23:06:03 +03:00
|
|
|
// Inner stores the error returned by external dependencies, e.g.: KeyFunc
|
|
|
|
Inner error
|
|
|
|
// Errors is a bit-field. See ValidationError... constants
|
|
|
|
Errors uint32
|
|
|
|
// Text can be used for errors that do not have a valid error just have text
|
|
|
|
text string
|
2015-04-09 23:20:10 +03:00
|
|
|
}
|
|
|
|
|
2021-08-03 16:51:01 +03:00
|
|
|
// Error is the implementation of the err interface.
|
2015-04-09 23:20:10 +03:00
|
|
|
func (e ValidationError) Error() string {
|
2016-06-16 02:42:50 +03:00
|
|
|
if e.Inner != nil {
|
|
|
|
return e.Inner.Error()
|
|
|
|
} else if e.text != "" {
|
|
|
|
return e.text
|
|
|
|
} else {
|
2015-04-09 23:20:10 +03:00
|
|
|
return "token is invalid"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-15 17:25:32 +03:00
|
|
|
// Unwrap gives errors.Is and errors.As access to the inner error.
|
|
|
|
func (e *ValidationError) Unwrap() error {
|
|
|
|
return e.Inner
|
|
|
|
}
|
|
|
|
|
2015-04-09 23:20:10 +03:00
|
|
|
// No errors
|
|
|
|
func (e *ValidationError) valid() bool {
|
2016-11-01 19:52:33 +03:00
|
|
|
return e.Errors == 0
|
2015-04-09 23:20:10 +03:00
|
|
|
}
|
2022-01-20 00:55:19 +03:00
|
|
|
|
2023-02-09 23:06:03 +03:00
|
|
|
// Is checks if this ValidationError is of the supplied error. We are first
|
|
|
|
// checking for the exact error message by comparing the inner error message. If
|
|
|
|
// that fails, we compare using the error flags. This way we can use custom
|
|
|
|
// error messages (mainly for backwards compatibility) and still leverage
|
|
|
|
// errors.Is using the global error variables.
|
2022-01-20 00:55:19 +03:00
|
|
|
func (e *ValidationError) Is(err error) bool {
|
|
|
|
// Check, if our inner error is a direct match
|
|
|
|
if errors.Is(errors.Unwrap(e), err) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we need to match using our error flags
|
|
|
|
switch err {
|
|
|
|
case ErrTokenMalformed:
|
|
|
|
return e.Errors&ValidationErrorMalformed != 0
|
|
|
|
case ErrTokenUnverifiable:
|
|
|
|
return e.Errors&ValidationErrorUnverifiable != 0
|
|
|
|
case ErrTokenSignatureInvalid:
|
|
|
|
return e.Errors&ValidationErrorSignatureInvalid != 0
|
|
|
|
case ErrTokenInvalidAudience:
|
|
|
|
return e.Errors&ValidationErrorAudience != 0
|
|
|
|
case ErrTokenExpired:
|
|
|
|
return e.Errors&ValidationErrorExpired != 0
|
|
|
|
case ErrTokenUsedBeforeIssued:
|
|
|
|
return e.Errors&ValidationErrorIssuedAt != 0
|
|
|
|
case ErrTokenInvalidIssuer:
|
|
|
|
return e.Errors&ValidationErrorIssuer != 0
|
|
|
|
case ErrTokenNotValidYet:
|
|
|
|
return e.Errors&ValidationErrorNotValidYet != 0
|
|
|
|
case ErrTokenInvalidId:
|
|
|
|
return e.Errors&ValidationErrorId != 0
|
|
|
|
case ErrTokenInvalidClaims:
|
|
|
|
return e.Errors&ValidationErrorClaimsInvalid != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|