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.
UpdatedIf 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
expwith 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
audandiss. 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,nbfandexpare Unix timestamps in seconds.- Decode to debug, verify on the server to trust.
Tools in this guide
More guides
- How to Extract Audio from a Video on Any Device2 MIN READThree free ways to pull the sound out of an MP4, MOV or WebM video on a phone or computer, with no app to install. Includes tips for speech and music.
- WebP vs PNG vs JPG: Which Image Format Should You Use?2 MIN READA plain comparison of JPG, PNG and WebP: file size, quality, transparency and compatibility, with a simple rule for picking the right format.
- How to Reduce Image File Size Without Losing Quality2 MIN READMake photos and screenshots smaller for email, uploads and websites. The three levers that matter: dimensions, format and quality, with recommended settings.
- What Is Base64 Encoding? A Plain-English Guide2 MIN READWhat Base64 is, how it turns bytes into text step by step, why it makes data 33% bigger, and where you meet it: data URIs, email, JWTs and APIs.