Authentication 2026-03-10

Fix Common JWT Token Decoding Errors

Debug JWT decode failures, expired token errors, signature validation issues, malformed headers, and algorithm confusion attacks.

🔓 Tool: JWT Decoder — Free

JWT tokens are three Base64url-encoded segments joined by dots. Each segment has strict rules, and a single character off breaks the entire token. This guide covers the seven most common JWT errors developers encounter.

Jump to error

  1. 1 Token is malformed (not three parts)
  2. 2 Token has expired
  3. 3 Algorithm mismatch (none or RS256 vs HS256)
  4. 4 Base64url padding causes decode error
  5. 5 Decoding succeeds but claims are not validated
1

Token is malformed (not three parts)

Error message
JsonWebTokenError: jwt malformed
Root cause

A valid JWT must have exactly three dot-separated segments: header.payload.signature. Missing dots or extra content breaks the structure.

Step-by-step fix

  1. 1 Paste the full token — including all three parts separated by periods.
  2. 2 Check you haven't accidentally included the 'Bearer ' prefix.
  3. 3 Verify no line breaks were introduced when copying the token.
  4. 4 Count the dots: a valid JWT has exactly two.
Wrong
Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIn0
Correct
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIn0.signature

2

Token has expired

Error message
TokenExpiredError: jwt expired (exp claim)
Root cause

The `exp` claim is a Unix timestamp in seconds. When the current time exceeds this value, the token is invalid.

Step-by-step fix

  1. 1 Paste the token into the JWT Decoder.
  2. 2 Inspect the `exp` field in the payload — it's a Unix timestamp.
  3. 3 Use the Timestamp Converter to check what date that corresponds to.
  4. 4 Request a new token from your auth server; do not extend the exp manually.
Wrong
// exp: 1700000000 — already in the past
{"sub": "user_123", "exp": 1700000000}
Correct
// exp should be current_time + token_lifetime
{"sub": "user_123", "exp": 1893456000}

3

Algorithm mismatch (none or RS256 vs HS256)

Error message
JsonWebTokenError: invalid algorithm
Root cause

The `alg` field in the JWT header must match the algorithm your server expects. The 'none' algorithm attack and RS256/HS256 confusion are common security issues.

Step-by-step fix

  1. 1 Decode the header (first segment) in the JWT Decoder.
  2. 2 Check the `alg` field — compare it to your server's expected algorithm.
  3. 3 Never accept tokens with `"alg": "none"` in production.
  4. 4 If using RS256, ensure you validate with the public key, not the HMAC secret.
Wrong
// Attacker-crafted token:
{"alg": "none", "typ": "JWT"}
Correct
// Valid production header:
{"alg": "HS256", "typ": "JWT"}

4

Base64url padding causes decode error

Error message
Error: Invalid base64url string
Root cause

JWT uses Base64url encoding (no `+` or `/`, no `=` padding). Standard Base64 decoders reject this format.

Step-by-step fix

  1. 1 Use the JWT Decoder tool which handles Base64url automatically.
  2. 2 If decoding manually, replace `-` with `+` and `_` with `/`.
  3. 3 Add padding: append `=` until the string length is a multiple of 4.
Wrong
// Standard base64 decode fails on JWT segments
atob(jwtSegment.replace(/-/g, '+').replace(/_/g, '/')) // missing padding
Correct
function decodeJwtSegment(seg) {
  const pad = seg + '==='.slice((seg.length + 3) % 4);
  return atob(pad.replace(/-/g, '+').replace(/_/g, '/'));
}

5

Decoding succeeds but claims are not validated

Error message
(No error — silent security bypass)
Root cause

The JWT Decoder only decodes — it does not verify the signature or validate claims. Never trust decoded claims without server-side signature verification.

Step-by-step fix

  1. 1 Use the decoder only for debugging/inspection.
  2. 2 In production, always verify the signature using your auth library.
  3. 3 Validate `iss` (issuer), `aud` (audience), and `exp` claims server-side.
  4. 4 Never use decoded payload data without verification.
Wrong
// INSECURE: trusting decoded JWT without verification
const payload = JSON.parse(atob(token.split('.')[1]));
const userId = payload.sub; // NEVER do this
Correct
// SECURE: verify first, then use
const payload = jwt.verify(token, SECRET_KEY);
const userId = payload.sub;

Frequently Asked Questions

Is it safe to paste my JWT token into the online decoder?

The JWT Decoder on toolpilot.dev runs entirely in your browser — no data is sent to any server. That said, avoid pasting production tokens with sensitive claims; use test tokens for debugging.

Why does my token decode fine locally but fail in production?

Common causes: clock skew (server time differs by more than the token's leeway), wrong secret key, or a different algorithm than expected. Check the `iat`, `exp`, and `alg` claims.

What is the difference between a JWT and a session token?

A JWT is self-contained — all claims are in the token itself. A session token is an opaque reference that requires a database lookup. JWTs are stateless but cannot be revoked without a blacklist.

Related Tools

Try the JWT Decoder now

Free, runs in your browser, no signup required. Learn more about JWT Decoder.

Open JWT Decoder →