hasura/graphql-engine · error · Error
JWT validation error: {0}
Error message
JWT validation error: {0} What it means
Wrapper around the underlying jsonwebtoken crate validation error ({0}). Signals that the token failed cryptographic or claims validation: invalid signature, expired token (exp), not-yet-valid (nbf), wrong issuer/audience, etc.
Source
Thrown at v3/crates/auth/hasura-authn-jwt/src/jwt.rs:62
#[error("Expected string value for claim {claim_name}")]
ClaimMustBeAString { claim_name: String },
#[error("Required claim {claim_name} not found")]
RequiredClaimNotFound { claim_name: String },
#[error("JWT Authorization token source: Header name {header_name} not found.")]
AuthorizationHeaderSourceNotFound { header_name: String },
#[error("JWT Authorization token source: Cookie header not found")]
CookieNotFound,
#[error(
"JWT Authorization token source: cookie name {cookie_name} not found in the Cookie header"
)]
CookieNameNotFound { cookie_name: String },
#[error("Error in parsing the {header_name} header: {err}")]
AuthorizationHeaderParseError { err: String, header_name: String },
#[error("Error in parsing the Cookie header value: {err}")]
CookieParseError { err: cookie::ParseError },
#[error("Missing corresponding value for the cookie with cookie name: {cookie_name}")]
MissingCookieValue { cookie_name: String },
#[error("JWT validation error: {0}")]
JWTValidationError(jwt::errors::Error),
#[error("Internal Error - {0}")]
Internal(#[from] InternalError),
}
impl TraceableError for Error {
fn visibility(&self) -> ErrorVisibility {
// For the purpose of traces, all JWT errors should be developer facing.
ErrorVisibility::User
}
}
#[derive(Debug, thiserror::Error)]
pub enum InternalError {
#[error("Error while constructing the JWT decoding key: {0}")]
JWTDecodingKeyError(jwt::errors::Error),
#[error("Error while decoding the JWT: {0}")]
JWTDecodingError(jwt::errors::Error),View on GitHub (pinned to 724551b9ae)
Solutions
- Inspect the inner jwt::errors::Error kind (ExpiredSignature / InvalidSignature / InvalidIssuer / InvalidAudience)
- Refresh the token if expired and retry with the new token
- Verify the JWKS endpoint / configured key matches the issuer and refresh cached keys
- Align iss/aud claims in metadata with what the IdP issues; check server clock skew
Example fix
// before: request with expired token // after: refresh access token, then request with new Bearer token
Defensive patterns
Strategy: retry
Validate before calling
const payload = decodeJwt(token); if (payload.exp * 1000 <= Date.now()) await refreshToken();
Type guard
const isExpired = (p: { exp?: number }): boolean => (p.exp ?? 0) * 1000 <= Date.now(); Try / catch
On ExpiredSignature, refresh the token once and retry the request; on InvalidSignature stop and alert (key mismatch is config-level).
Prevention
- Preemptively refresh tokens before exp
- Refresh JWKS cache on UnknownKey kid errors
- Align iss/aud config with the IdP
When it happens
Trigger: The token is well-formed and extracted, but fails validation — expired `exp`, signature not matching the configured key/JWKS, `iss`/`aud` mismatch, or malformed token structure.
Common situations: Expired tokens after long idle sessions; rotated signing keys with stale JWKS cache; wrong issuer/audience config; clock skew between servers causing premature expiry.
Related errors
- Session variable not found: {name}
- Error while parsing the claims map entry: {claim_name} - {er
- Expected string value for claim {claim_name}
- Required claim {claim_name} not found
- JWT Authorization token source: Header name {header_name} no
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/9146cbd22b031317.
Report an issue: GitHub.