Understanding JWTs: structure, claims, and how to inspect one safely

A JWT is signed, not encrypted. Anyone holding it can read every claim inside. This guide covers the anatomy, the claims worth checking, and the mistakes that turn a token into an incident.

By Sk Md Rakib · Published · Updated · 8 min read

Three parts, two dots

A JSON Web Token is three Base64URL-encoded segments joined by dots: header, payload, signature. The header declares the algorithm and key id. The payload holds the claims. The signature covers the first two segments so a server can detect tampering.

Base64URL is an encoding, not encryption. It exists so the token survives URLs and HTTP headers — it provides exactly zero confidentiality. Decoding a JWT requires no key, no permission and no tooling beyond a browser. That single fact drives every rule that follows.

The claims that matter in practice

Registered claims are three-letter keys defined by the spec, and in real debugging you look at the same few every time:

  • exp — expiry as a Unix timestamp in seconds. Off-by-1000 bugs from milliseconds are extremely common.
  • iat — issued-at, useful for spotting clock skew between services.
  • nbf — not-before; a token can be structurally fine and still be rejected as 'too early'.
  • iss and aud — issuer and audience. Mismatched audience is the top cause of 'valid token, still 401'.
  • sub — the subject, usually the user id your application actually cares about.

Decoding is not verifying

A decoder shows you what a token claims. It cannot tell you whether those claims are trustworthy, because verification requires the signing key — an HMAC secret, or the issuer's public key for RSA and ECDSA. Never make an authorisation decision from a decoded payload on the client. The browser is the one place where the attacker controls the input.

The historical alg:none attack is the clearest illustration: change the header to none, strip the signature, and a naive library that trusts the declared algorithm accepts a forged token. Modern libraries reject this, but the lesson generalises — verification must pin the expected algorithm and key on the server side rather than believing the header.

Inspecting a token without creating an incident

The tokens you most want to inspect are usually live credentials pulled from a running session, so treat them like passwords. Use a decoder that runs entirely in your browser, confirm in the Network tab that nothing is posted, and prefer an expired or staging token whenever the claim shape is all you need.

  • Never paste a production access token into a server-backed decoder or a chat message.
  • If a live token has been exposed, rotate it — decoding leaves no trace, but sharing does.
  • Keep tokens out of URLs and out of localStorage where scripts can read them.
  • Log claim names when debugging, never whole tokens.

Design choices that prevent JWT pain

Keep access tokens short-lived and pair them with a refresh mechanism, so a leak has a small blast radius. Keep payloads small: every request carries them, and a bloated token with embedded profile data becomes a performance problem and a privacy problem at once. Never put anything in a JWT you would not be willing to hand to the user — because you are handing it to them.

Finally, decide deliberately whether you need a JWT at all. Opaque session identifiers backed by server-side storage are easier to revoke, and revocation is the single hardest thing about stateless tokens.

// tools referenced in this guide

// more guides