← All guides

JWT Explained: Structure, Claims, and How to Read One

JSON Web Tokens are everywhere in modern authentication, and they trip people up for one reason: they look encrypted but they are not. A JWT is a compact, signed bundle of JSON that a server can hand to a client and later verify without looking anything up in a database. Once you can read the three parts, the whole thing stops being mysterious.

The shape of a token

A JWT is three chunks of text joined by dots, so it always has exactly two dots: header.payload.signature. Each chunk is Base64url encoded with the URL-safe variant of Base64, so the token can sit inside an HTTP header or a link without being mangled. Decode the first two chunks and you get plain JSON; the third is a binary signature.

Part 1: the header

The header is a small JSON object that says how the token is signed. It typically holds two fields: alg, the signing algorithm (for example HS256 or RS256), and typ, which is almost always JWT. That is it. The header is just metadata telling the verifier which method to use.

Part 2: the payload (the claims)

The payload carries the claims, the statements about the user and the token itself. Some claim names are standardised:

  • sub: the subject, usually the user ID.
  • iat: issued-at, a Unix timestamp of when the token was created.
  • exp: expiry, a Unix timestamp after which the token must be rejected.
  • iss and aud: who issued the token and who it is intended for.

Alongside these you can add your own claims, such as a role or a plan tier. Keep the payload small: it travels on every request, and bloated tokens slow everything down.

The payload is readable by anyone. Base64url is encoding, not encryption, so a token is not a place to store anything you would not happily print. Sensitive data belongs server-side.

Part 3: the signature

The signature is what makes a JWT trustworthy. The server takes the encoded header and payload, runs them through the algorithm named in the header together with a secret (or a private key), and attaches the result. When the token comes back, the server recomputes the signature and checks it matches. Change one character of the header or payload and the signature no longer lines up, so the token is rejected. This is the same integrity idea behind hashing: prove nothing was altered.

Signed is not secret

This is the single most important point. A signature guarantees integrity and authenticity (the token really came from your server and was not tampered with), but it does not provide confidentiality. Anyone who intercepts the token can read every claim inside. If you genuinely need the contents hidden, that is a separate, less common standard (JWE) that actually encrypts the payload.

HS256 vs RS256, briefly

HS256 uses one shared secret to both sign and verify. That is simple, but every verifier needs the secret. RS256 signs with a private key and verifies with a public key, so you can hand the public key to many services without letting any of them mint tokens. Pick RS256 when tokens cross trust boundaries; HS256 is fine inside a single app you fully control.

Reading a token safely

To inspect a token, paste it into a JWT decoder and read the header and payload. A good decoder does this entirely in your browser, which matters: a real token is a live credential, so you should never paste one into a site that sends it to a server. Decoding shows you the claims and the expiry; it does not, and cannot, verify the signature without the key.

Frequently asked questions

Is the data inside a JWT encrypted?

No. A standard JWT payload is only Base64url-encoded, so anyone holding the token can read it. The signature stops tampering, but it does not hide the contents. Never put secrets in a normal JWT.

What does the signature actually prove?

It proves the token was issued by someone holding the signing key and has not been changed since. If a single character of the header or payload is altered, the signature no longer matches and the token is rejected.

Why are there two dots in a JWT?

A JWT has three parts: header, payload and signature. Each part is Base64url-encoded and the three are joined with dots, which is why you see two dots separating them.

What is the difference between exp and iat?

iat is the issued-at time, recording when the token was created. exp is the expiry time, after which the token should be rejected. Both are usually stored as Unix timestamps in seconds.