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)

Most upvoted comments

if you would be open to also add the errors…

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.