Your files stay with you.
Guide · 3 min read

How JWTs Work: Reading the Header, Payload and Signature

A clear explanation of JSON Web Tokens: what the three parts contain, what claims like exp and iat mean, why decoding is not the same as verifying, and how to keep tokens safe.

Updated

If you work with web apps or APIs, you have probably seen a long string that starts with eyJ and contains two dots. That is a JSON Web Token, or JWT (often pronounced “jot”). JWTs are used to prove who a user is and what they are allowed to do, and knowing how to read one makes login and permission bugs much easier to solve.

The three parts

A JWT is three pieces of text joined by dots:

header.payload.signature

The first two parts are JSON objects that have been encoded with Base64URL, a variant of Base64 that is safe to put in URLs. The third part is a cryptographic signature. Because of the encoding, every JWT header begins with eyJ, which is simply how {" looks in Base64.

The header

The header says how the token was signed. A typical header looks like this:

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

alg is the signing algorithm. HS256 uses a shared secret; RS256 and ES256 use a private key to sign and a public key to verify. Some headers also include kid, a key ID that tells the server which key to check against.

The payload

The payload holds the claims: statements about the user and the token itself. Some claim names are standard:

  • sub (subject): who the token is about, usually a user ID.
  • iss (issuer): who created the token, such as your login server.
  • aud (audience): which service the token is meant for.
  • iat (issued at): when the token was created.
  • exp (expires): when the token stops being valid.
  • nbf (not before): the earliest time the token may be used.

The three time claims are Unix timestamps, counted in seconds. A value like 1793300000 means little at a glance, which is why the JWT Decoder shows each one as a readable date and tells you whether the token has already expired. Apps can add their own claims too, such as role, email or scope.

The signature

The server builds the signature from the encoded header, the encoded payload and a secret key. If anyone changes even one character of the payload, the signature no longer matches and the server rejects the token. This is what stops a user from editing "role": "user" to "role": "admin".

Decoding is not verifying

This is the most important point about JWTs. The header and payload are encoded, not encrypted. Anyone who has the token can decode it and read every claim, with no key at all. Decoding tells you what a token says. It does not tell you whether the token is genuine.

Verifying means recomputing the signature with the correct key and checking that it matches, and checking that the token has not expired. Only your server, which holds the key, should make that decision. A decoder is a debugging tool: it helps you see why a request was rejected, but it should never be used to decide whether to trust a token.

Two practical consequences follow:

  • Never put secrets in a JWT payload. Passwords, card numbers and private notes would be readable by anyone who sees the token.
  • Always verify on the server. Accepting a token without checking the signature, or accepting tokens with "alg": "none", is a classic security hole.

Common problems a decoder helps you spot

  • “Token expired” errors. Compare exp with the current time. If tokens expire sooner than expected, check whether the issuer’s clock is wrong or whether the lifetime is shorter than you thought.
  • “Invalid audience” or “invalid issuer”. Look at aud and iss. A token from your staging login server will not be accepted by production.
  • Missing permissions. Check whether the role or scope claim contains what the API expects.
  • Malformed token. A JWT must have exactly two dots. Copying from logs often cuts off the end or adds a quote or a space.

Keeping tokens safe

A valid JWT works like a temporary password: whoever holds it can act as the user until it expires. Treat tokens from real accounts with care. Don’t paste them into tools that send data to a server, don’t post them in public issue trackers, and keep their lifetimes short. The JWT Decoder on this site runs entirely in your browser, so the token is never uploaded, but it is still good practice to use test accounts when you share screenshots or logs.

Summary

  • A JWT is header.payload.signature, with the first two parts in Base64URL.
  • Anyone can read the payload; the signature only proves it wasn’t changed.
  • iat, nbf and exp are Unix timestamps in seconds.
  • Decode to debug, verify on the server to trust.

Tools in this guide

More guides