How to debug invalid JWT errors
June 30, 2026 · 15 min read
"Invalid JWT" in logs rarely tells you enough. Gateways and frameworks emit variants: JsonWebTokenError, TokenExpiredError, ERR_JWS_SIGNATURE_VERIFICATION_FAILED. This playbook maps messages to causes and fixes without guessing.
Common error symptoms
- Malformed - wrong segment count, invalid Base64URL, non-JSON payload.
- Invalid signature - wrong secret, rotated key, truncated token copy.
- Expired -
expin the past or clock skew without leeway. - Invalid aud/iss - token from staging IdP hitting production API.
Malformed token issues
JWTs must have exactly two dots. Wrapping quotes, Bearer prefix pasted into decoders, or URL-encoding breaks parsing. Trim whitespace and ensure you did not copy only the first line of a multi-line log entry.
function extractBearer(header) {
if (!header?.startsWith("Bearer ")) throw new Error("Missing Bearer prefix");
return header.slice(7).trim();
}
Signature verification failures
Confirm the API uses the same algorithm as the issuer (alg in header). For HS256, secrets must match byte-for-byte - check for trailing newline in env vars. For RS256, ensure JWKS kid matches and PEM has correct line endings. Re-sign a test payload in the generator and compare segment three length.
Claim validation errors
Decode locally and compare iss, aud, and exp to your config. Multi-audience tokens may arrive as a string or array - your validator must accept the shape you issue. If nbf is a few seconds in the future, wait or fix clock sync.
Structured debug playbook
- 1. Reproduce with curl and a single token; remove gateway variables.
- 2. Decode header and payload; note alg, kid, exp, iss, aud.
- 3. Verify offline with the same key material as production (never in public tools for real secrets).
- 4. Diff working vs broken tokens claim-by-claim.
- 5. Add integration test with golden token from your IdP.
FAQ
- Why does jwt.io say valid but my API rejects?
- jwt.io may not check your iss, aud, or signing key. Your API enforces stricter rules.
- Can trailing newline in SECRET break HS256?
- Yes. Environment loaders often include hidden characters. Log secret length, not value.
- What does kid mismatch mean?
- The header’s key ID does not match any key in your JWKS. Common after key rotation if cache is stale.
- How do I test expiry without waiting?
- Issue a token with past exp in a dev environment, or mock time in unit tests - not in production verifiers.
Related: JWT expiration · Security mistakes