go-kit/kit · error · ErrTokenInvalid
JWT was invalid
Error message
JWT was invalid
What it means
Returned by jwt.NewParser when jwt.ParseWithClaims succeeded without error but token.Valid is still false. It is the generic 'validation failed' outcome: the token was syntactically parseable and not expired/malformed/not-yet-active, but the signature or claims check rejected it without a more specific ValidationError bit being set.
Source
Thrown at auth/jwt/middleware.go:33
JWTContextKey contextKey = "JWTToken"
// JWTTokenContextKey is an alias for JWTContextKey.
//
// Deprecated: prefer JWTContextKey.
JWTTokenContextKey = JWTContextKey
// JWTClaimsContextKey holds the key used to store the JWT Claims in the
// context.
JWTClaimsContextKey contextKey = "JWTClaims"
)
var (
// ErrTokenContextMissing denotes a token was not passed into the parsing
// middleware's context.
ErrTokenContextMissing = errors.New("token up for parsing was not passed through the context")
// ErrTokenInvalid denotes a token was not able to be validated.
ErrTokenInvalid = errors.New("JWT was invalid")
// ErrTokenExpired denotes a token's expire header (exp) has since passed.
ErrTokenExpired = errors.New("JWT is expired")
// ErrTokenMalformed denotes a token was not formatted as a JWT.
ErrTokenMalformed = errors.New("JWT is malformed")
// ErrTokenNotActive denotes a token's not before header (nbf) is in the
// future.
ErrTokenNotActive = errors.New("token is not valid yet")
// ErrUnexpectedSigningMethod denotes a token was signed with an unexpected
// signing method.
ErrUnexpectedSigningMethod = errors.New("unexpected signing method")
)
// NewSigner creates a new JWT generating middleware, specifying key ID,
// signing string, signing method and the claims you would like it to contain.View on GitHub (pinned to 78fbbceece)
Solutions
- Confirm the keyfunc returns exactly the key the signer used — log the kid header and compare
- Check issuer/audience/subject claim values against what the identity provider actually emits
- Verify both sides use the same signing method in NewSigner and NewParser
- Print the underlying jwt.ValidationError bits in a debug build to see which check failed before go-kit collapses it to ErrTokenInvalid
Example fix
// before: keyfunc ignores kid and always returns the current key
kf := func(*jwt.Token) (interface{}, error) { return []byte("new-secret"), nil }
// after: resolve the key by kid so old and new tokens both verify
var keys = map[string][]byte{"k1": []byte("old-secret"), "k2": []byte("new-secret")}
kf := func(t *jwt.Token) (interface{}, error) {
kid, _ := t.Header["kid"].(string)
if k, ok := keys[kid]; ok {
return k, nil
}
return nil, errors.New("unknown kid")
} Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
resp, err := ep(ctx, req)
if err != nil {
switch {
case errors.Is(err, jwt.ErrTokenInvalid):
// 401: signature/claims failed — force re-authentication, do not blind-retry
case errors.Is(err, jwt.ErrTokenExpired):
// 401: refresh token then retry once
}
} Prevention
- Resolve verification keys by the kid header so multi-key rotations verify correctly
- Keep a single source of truth for issuer/audience values shared by signer and parser
- Log the raw jwt.ValidationError bitfield at debug level before go-kit flattens it to ErrTokenInvalid
When it happens
Trigger: The keyfunc returned a different key than the one used to sign (wrong secret, wrong public key, wrong kid resolution); claims-based validation (issuer, subject, audience via the v4 validator) failed without the malformed/expired/nbf bits; parser and signer disagree on signing method family so the signature check fails; token was tampered with so the signature simply doesn't verify.
Common situations: Rotating secrets where old tokens are verified with the new key; multi-environment setups sharing tokens across envs with different keys; keyfunc that ignores the kid header and always returns one key; subtle claim mismatches (iss URL with/without trailing slash) after an identity-provider change.
Related errors
- token up for parsing was not passed through the context
- JWT is expired
- JWT is malformed
- token is not valid yet
- unexpected signing method
AI-assisted analysis of go-kit/kit@78fbbceece (2026-08-15).
Data as JSON: /api/errors/31382d40f64ace6e.
Report an issue: GitHub.