JWT decoded: structure, claims, and security pitfalls

7 min readUpdated May 24, 2026

A JWT is a compact, URL-safe token that carries claims between parties. It is everywhere in modern auth — and frequently misused. Here is how it is built, what is inside, and where security goes wrong.

Anatomy of a token

A JWT is three Base64URL-encoded parts joined by dots: header.payload.signature.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjMiLCJuYW1lIjoiYWRhIn0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

The header names the signing algorithm. The payload holds the claims. The signature proves the first two parts were not tampered with. Decode any token in the JWT Decoder.

Standard claims worth knowing

  • iss — issuer: who created the token.
  • sub — subject: usually the user ID.
  • aud — audience: who the token is for.
  • exp — expiry: a Unix timestamp after which the token is invalid.
  • iat — issued-at: when it was created.
  • nbf — not-before: do not accept the token before this time.

The exp claim is in seconds, not milliseconds. To check expiry: exp * 1000 < Date.now().

Decoding is not verifying

This is the single most important point: anyone can decode a JWT. It is just Base64 — not encryption. Never put secrets in the payload.

Decoding reads the claims. *Verifying* recomputes the signature with the secret/public key and confirms it matches. A decoder shows you what is inside; only verification tells you the token is authentic and untampered.

Treat the payload as public. If you can read a password or API key in a token you decoded, so can an attacker.

Security pitfalls to avoid

  1. The alg: none attack — reject tokens whose algorithm is none on the server.
  2. Algorithm confusion — pin the expected algorithm; do not let the token choose between HMAC and RSA.
  3. Ignoring exp — always check expiry server-side; a decoded "VALID" badge is informational only.
  4. Storing JWTs in localStorage — vulnerable to XSS; prefer httpOnly cookies for session tokens.

Frequently asked questions

Can I trust a JWT just because it decoded successfully?
No. Decoding only reads the Base64 parts. You must verify the signature with the issuer’s secret or public key, and check exp/nbf/aud, before trusting anything.
Are JWTs encrypted?
Standard signed JWTs (JWS) are not encrypted — they are signed. The payload is readable by anyone. If you need confidentiality, use JWE (encrypted JWT) or simply keep secrets out of the token.
Why is my token "expired" right after creation?
Usually a units bug: exp is in seconds since epoch, but the code compared it against milliseconds. Multiply exp by 1000 before comparing to Date.now().
Where should I store a JWT in the browser?
For session auth, an httpOnly, Secure cookie is safer than localStorage because it is not readable by JavaScript, reducing XSS risk.

Try it yourself

Put this guide into practice — these tools run free in your browser.