How to debug invalid JWT errors - cover art

JWT and security 15 min read

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 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

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

Browse all tools