What’s inside a JWT? Decoding and verifying JSON Web Tokens

JSON Web Tokens (JWTs) are everywhere in modern web development — they power login sessions, API authentication and single sign-on. But the first time you see one, it looks like a meaningless wall of characters. This guide breaks a JWT into its three parts, shows you how to read what is inside one, and explains how to tell a valid token from a forged one.

What a JWT actually is

A JWT is just a string with three parts separated by dots: header.payload.signature. Each part is Base64url-encoded (a URL-safe variant of Base64), which is why it looks scrambled but is not actually encrypted. That is the single most important thing to understand: a JWT is encoded, not encrypted. Anyone can read the contents. The signature is what stops them changing it.

Part 1: the header

Decode the first segment and you get a small JSON object describing how the token was signed:

{ "alg": "HS256", "typ": "JWT" }

alg is the signing algorithm (more on that below) and typ is the token type. That is usually all you will find here.

Part 2: the payload (the claims)

The middle segment is the interesting one. It holds the “claims” — statements about the user and the token itself. Some claim names are standardised:

  • iss — issuer: who created the token
  • sub — subject: usually the user ID the token represents
  • aud — audience: who the token is intended for
  • exp — expiry: a Unix timestamp after which the token is invalid
  • iat — issued at: when the token was created
  • nbf — not before: the token is invalid until this time
  • jti — a unique ID for the token

Those exp, iat and nbf values are Unix timestamps, so a quick way to sanity-check a token is to run them through a timestamp converter. Alongside the standard claims you will usually find custom ones — a username, a role, a list of permissions — whatever the application chose to include.

Part 3: the signature

The third segment is the security. The server takes the encoded header and payload and signs them. With an HMAC algorithm like HS256 it uses a single secret key that both signs and verifies. With an RSA or ECDSA algorithm like RS256 it signs with a private key and anyone can verify with the matching public key — which is how single sign-on providers let many services trust the same token.

If someone changes a single character of the payload — say, flipping "role": "user" to "role": "admin" — the signature no longer matches, and any server that checks it will reject the token.

Reading a token safely

Because the payload is readable, never put anything secret in it — no passwords, no API keys, no personal data you would not want exposed. Treat it as public information signed for integrity, not privacy. A few more rules worth knowing:

  • Always verify the signature before trusting any claim. Decoding is not verifying.
  • Reject alg: none. Some older libraries accepted unsigned tokens — a classic vulnerability.
  • Check exp. An expired token should never be accepted, however valid the signature.
  • Keep your signing secret long and random. A weak HMAC secret can be brute-forced offline.

Try it yourself

The fastest way to understand a JWT is to pull one apart. Our free ateByteApps DevTools includes a JWT decoder that splits any token into its header, payload and signature and shows the decoded claims instantly — and because it runs entirely in your browser, the token never leaves your machine. Paste one in and the structure above will click into place.

  3 comments for “What’s inside a JWT? Decoding and verifying JSON Web Tokens”

Leave a Reply

Your email address will not be published. Required fields are marked *