Skip to content

Error Handling

CyberGo JWT uses the sentinel errors pattern. All errors are checked with errors.Is().

Basic Pattern

go
claims, valid, err := processor.Validate(tokenString)
if err != nil {
    switch {
    case errors.Is(err, jwt.ErrTokenExpired):
        // Token expired
    case errors.Is(err, jwt.ErrTokenRevoked):
        // Token revoked
    case errors.Is(err, jwt.ErrTokenInvalidIssuer):
        // Issuer mismatch
    case errors.Is(err, jwt.ErrTokenInvalidAudience):
        // Audience mismatch
    case errors.Is(err, jwt.ErrInvalidToken):
        // Invalid signature or format
    case errors.Is(err, jwt.ErrProcessorClosed):
        // Processor is closed
    default:
        // Other errors
    }
}

Use errors.Is()

Don't use err == jwt.ErrTokenExpired or string matching. errors.Is() correctly handles wrapped errors.

Error Categories

Configuration Phase

jwt.New() may return these errors:

ErrorCauseSolution
ErrInvalidConfigMultiple invalid config fieldsCheck Config fields
ErrInvalidSecretKeyHMAC key under 32 bytes or weak keyUse a stronger key
ErrInvalidSigningMethodUnsupported signing algorithmUse one of 12 built-in algorithms

Token Operations

ErrorMethodSuggestion
ErrEmptyTokenAll token operation methodsCheck request header
ErrInvalidTokenValidate, Refresh, ValidateInto, RefreshInto, Revoke, IsRevokedSignature mismatch, deny access
ErrAlgorithmMismatchValidate, Refresh, ValidateInto, RefreshIntoToken algorithm doesn't match config, deny access
ErrExpirationRequiredValidate, Refresh, ValidateInto, RefreshIntoRequireExpiration enabled but token lacks exp claim
ErrTokenTypeMismatchRefresh, RefreshIntoAccess token (token_type=access) used to refresh, deny access
ErrTokenExpiredValidate, Refresh, ValidateInto, RefreshIntoPrompt user to refresh token
ErrTokenNotValidYetValidate, Refresh, ValidateInto, RefreshIntoCheck clock synchronization
ErrTokenInvalidIssuerValidate, Refresh, ValidateInto, RefreshInto, Revoke, IsRevokedIssuer mismatch
ErrTokenInvalidAudienceValidate, Refresh, ValidateInto, RefreshInto, Revoke, IsRevokedAudience mismatch
ErrTokenRevokedValidate, Refresh, ValidateInto, RefreshIntoToken revoked, deny access
ErrInvalidClaimsCreate, CreateRefresh, Validate, Refresh, ValidateInto, RefreshIntoBusiness validation failed
ErrTokenMissingIDRevoke, IsRevokedToken missing jti

Rate Limiting & Blacklist

ErrorMethodSuggestion
ErrRateLimitExceededCreate, CreateRefresh, Refresh, RefreshIntoReturn 429
ErrBlacklistNotConfiguredRevokeConfigure blacklist

Lifecycle

ErrorMethodSuggestion
ErrProcessorClosedAll methodsRecreate Processor
ErrStoreClosedRevoke, etc.Storage closed

Error Types

ValidationError

Returned on field-level validation failure, containing specific field and error info:

go
type ValidationError struct {
    Field   string  // Field name that failed
    Message string  // Error description
    Err     error   // Inner error
}

Error Handling in Web Services

go
func handleProtected(w http.ResponseWriter, r *http.Request) {
    tokenString := extractToken(r)
    claims, valid, err := processor.Validate(tokenString)
    if err != nil {
        switch {
        case errors.Is(err, jwt.ErrTokenExpired):
            http.Error(w, "token expired", http.StatusUnauthorized)
        case errors.Is(err, jwt.ErrTokenRevoked):
            http.Error(w, "token revoked", http.StatusUnauthorized)
        case errors.Is(err, jwt.ErrInvalidToken):
            http.Error(w, "invalid token", http.StatusUnauthorized)
        default:
            http.Error(w, "auth failed", http.StatusUnauthorized)
        }
        return
    }
    if !valid {
        http.Error(w, "invalid token", http.StatusUnauthorized)
        return
    }
    // Process request
}

Next Steps