jwx: Return custom errors for most common cases instead of generic `Error` or `ValidationError`
Abstract While building my own HTTP handler to verify a JWT token, I realized that besides some validation errors this lib always returns generic errors. The problem with this approach is that I have no way to know what the error really is, besides parsing the message, and this make things complex in case a specific error should be returned upstream. For example, I may want to return a different HTTP response if the parsing of the token has failed or if the signature is invalid.
Describe the proposed solution/change Below I prepared a comparison between 3 common libs I found in the Internet to work with JWT. I listed the errors I would like to be able to distinguish while parsing a token and whether each lib returns a specific error type for each case or not.
lestrrat-go/jwx |
golang-jwt/jwt |
square/go-jose |
|
---|---|---|---|
ErrTokenMalformed |
No | Yes | No |
ErrTokenSignatureInvalid |
No | Yes | No |
ErrTokenInvalidAudience |
Yes (no specific error) | Yes | Yes |
ErrTokenExpired |
Yes | Yes | Yes |
ErrTokenUsedBeforeIssued |
Yes | Yes | Yes |
ErrTokenInvalidIssuer |
Yes (no specific error) | Yes | Yes |
ErrTokenNotValidYet |
Yes | Yes | Yes |
ErrTokenInvalidId |
Yes (no specific error) | Yes | Yes |
ErrTokenInvalidClaims |
Yes (no specific error) | Yes | Yes |
From what you can see above, most of the errors are already handled, but it is impossible to distinguish them because they are all instances of ValidationError
. The first two are really important to me, as I suspect that many users would like to return to the caller whether a token has an invalid format, and right now the error is just a plain fmt.Errorf()
. Implementing custom errors for those cases would allow people to do:
token, err := jwt.ParseString(...)
if err == nil {
fmt.Println("Have a nice day")
} else if errors.Is(err, ErrTokenMalformed) {
fmt.Println("That's not even a token")
} else if errors.Is(err, ErrTokenSignatureInvalid) {
fmt.Println("You are trying to fool me")
} else {
fmt.Println("Could not handle this token", err)
}
Analysis
A workaround may be to parse the error message and return a custom error depending on the outcome. This is the solution chosen by go-chi/jwtauth
. Unfortunately, as you can imagine, it can easily break and it isn’t maintenable in the long term.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 18 (8 by maintainers)
Yes, but please follow the existing pattern (see #714). I really don’t want to expose error types. This is because once you expose error types, it becomes really hard to modify them in the future. We had limited access to error types by only exposing an interface and functions to return the error for this. Things would be different if users could write
jwt.SomeRandomError{}
in their code.