All posts

JWT explained — how to read and verify a JSON Web Token

A no-nonsense guide to what a JWT actually is, what each part means, how signatures work, and how to decode and verify one safely.

24 May 20265 min readBy Primova
jwtauthsecurityweb-tokens

A JWT looks like someone fell asleep on the keyboard: three chunks of gibberish separated by dots. But there's nothing mysterious in there. It's just data you can read in about five seconds — and the most important thing to understand about it is also the thing people get wrong most often. So let's clear that up first.

The one misconception to kill

A JWT is not encrypted. It's signed. Those are completely different.

Anyone who has the token can read everything inside it. The dots split it into three Base64 parts, and Base64 isn't a secret code — it's just text encoding. Paste any JWT into a decoder and the contents pop right out, no password needed. The signature doesn't hide the data; it proves the data hasn't been changed.

So: don't put anything secret in a JWT. No passwords, no API keys, nothing you wouldn't be comfortable printing on a postcard. Treat the payload as public.

The three parts

A JWT is always header.payload.signature — three Base64 sections joined by dots:

The anatomy of a tokeneyJhbGc....eyJzdWIiOiI3Iiwi....SflKxwRJ...HEADERwhich algorithmPAYLOADthe claims (readable by anyone)SIGNATUREproves it's untamperedThe header and payload are just Base64 — decode them and read them. Only the signature needs a secret.

Header — a tiny bit of JSON saying which algorithm signed the token, usually { "alg": "HS256", "typ": "JWT" }.

Payload — the actual contents, where the claims live. A few field names are standardised and worth knowing:

  • sub — the subject, usually the user ID
  • iss — who issued it
  • aud — who it's intended for
  • iat — issued at (a Unix timestamp)
  • nbf — not valid before
  • exp — when it expires

Those last three trip people up because they're raw Unix timestamps, not dates — 1717000000 instead of anything readable. A good decoder converts them for you and tells you "expires in 2 days" so you can spot a dead token at a glance.

Signature — the part that does the real work, covered next.

How the signature actually proves anything

When a server issues a token, it takes the header and payload, runs them through a hashing algorithm together with a secret only it knows, and tacks the result on as the signature.

Later, when the token comes back, the server repeats the exact calculation with its secret. If the result matches the signature on the token, two things are true: the token came from something holding that secret, and nobody altered the payload in transit. Change a single character of the payload and the signature no longer matches — the token is rejected.

That's why you can hand a JWT to the user and trust it later. Not because it's hidden, but because it can't be tampered with without you noticing.

The catch: this only works if you actually verify the signature. Decoding a token (reading it) and verifying it (checking it's legit) are different operations — and skipping the second one is a genuine security hole. A token whose contents you trust without checking the signature is a token an attacker can forge.

HS256 vs RS256, briefly

You'll see two families of algorithms:

  • HMAC (HS256/384/512) — one shared secret signs and verifies. Simple, common, fine when the same system does both ends.
  • RSA/ECDSA (RS256, ES256…) — the issuer signs with a private key; anyone can verify with the matching public key. Used when the thing verifying isn't the thing that issued the token — third-party auth, microservices, anywhere you want to verify without being able to mint new tokens.

For HMAC tokens you can verify a signature anywhere you have the secret. For the asymmetric ones you only need the issuer's public key.

Reading and checking one safely

The safe way to inspect a token is to do it locally — never paste a production token into a random website, because you're handing over a live credential. Primova's JWT Decoder runs entirely in your browser: the token and any secret you enter never get sent anywhere.

Drop a token in and you get the decoded header and payload, plus a plain-English table of the claims with the timestamps turned into real dates and relative times. Enter the shared secret and it'll verify an HMAC signature on the spot — Valid or Invalid, no guessing. You can even edit the payload and watch it re-sign live, which is handy for crafting test tokens.

It's the fastest way to answer the three questions you usually have about a token: what's in it, is it still valid, and was it actually signed by who it claims. Try it on a token at the JWT Decoder.