Back to blog

JWTs Explained: What's Actually Inside That Token

August 3, 2026

46 reads

A glowing digital token split into three connected segments

If you've ever pasted a JWT into a decoder and been surprised that you could just... read it, that's not a bug. That's the entire design. Here's what's actually going on.

Three parts, separated by dots

A JWT (JSON Web Token) is just three base64url-encoded chunks joined by periods: header.payload.signature. Each part has one job:

  • Header — says which algorithm was used to sign the token (usually HS256 or RS256).
  • Payload — the actual data: who this token represents, what they're allowed to do, when it expires. This is called the set of "claims."
  • Signature — a cryptographic proof that the header and payload haven't been tampered with since the server issued them.

Paste any JWT into JWT Decoder and you'll see exactly this: header and payload as readable JSON, signature as an opaque string.

The part that surprises people: it's encoded, not encrypted

Base64 is not encryption — it's just a reversible text encoding, the same way you could describe a number in binary or hex. Anyone who gets hold of a JWT, including a user inspecting their own browser's network tab, can decode the payload and read every claim in it. No secret key required.

This is by design — a JWT is meant to be inspectable, so any service that receives it can read the claims directly instead of calling back to a database. What the signature protects is integrity, not confidentiality: it proves the payload hasn't been altered, but it does nothing to hide what's in it.

The practical consequence: never put a password, API key, or anything actually secret into a JWT payload. If it's sensitive, it doesn't belong in the token — a user ID, a role, or an expiry timestamp is exactly what payloads are for.

What the signature actually stops

The signature is generated using a secret key (for HS256) or a private key (for RS256) that only the issuing server holds. If someone edits the payload — say, changing "role": "user" to "role": "admin" — the signature no longer matches, and any server correctly verifying the token will reject it.

This is why the verification step matters as much as the token itself. A JWT that's never checked against its signature is just an unverified claim someone is making about themselves — the security comes entirely from the receiving server actually validating it before trusting anything inside.

Building and inspecting tokens

  • Use JWT Decoder to paste in any token and instantly see its header, payload, and signature broken out — handy for debugging why an API call is being rejected, or checking an exp (expiry) claim without writing any code.
  • Use JWT Encoder to build a token with a custom payload and secret — useful for testing an API locally before wiring up real authentication.

Two habits worth keeping

  1. Always check exp. Most authentication bugs involving JWTs come down to expired tokens being accepted, or tokens with no expiry at all. Set one, and check it server-side on every request.
  2. Verify signatures server-side, always. Never trust a claim in a payload just because the token "looks valid" — decoding is not the same as verifying, and only signature verification actually confirms the token wasn't forged or altered.