A JSON Web Token (JWT) is a compact string used to carry claims between two parties, usually an identity provider and an application. It looks like three chunks of scrambled text joined by dots. Decoding it — turning those chunks back into readable JSON — is straightforward once you know the structure.
The three parts
A JWT is header.payload.signature, each part Base64URL-encoded:
- Header — metadata, usually the signing algorithm and token type.
- Payload — the claims: who the user is and any data the app needs.
- Signature — a cryptographic value used to prove the token was issued by the expected party and not altered.
Decoding step by step
- Split the string on the dots into three parts.
- Base64URL-decode the first part and parse it as JSON: the header.
- Base64URL-decode the second part and parse it as JSON: the payload.
- Leave the signature encoded — it is binary, not readable text.
For example, the header often decodes to {"alg":"HS256","typ":"JWT"} and a payload to {"sub":"1234567890","name":"Ada Lovelace","iat":1767225600,"exp":1767229200}.
Reading the standard claims
| Claim | Meaning |
|---|---|
sub | Subject — usually the user identifier. |
iss | Issuer — who created the token. |
aud | Audience — who the token is intended for. |
iat | Issued at, as a Unix timestamp in seconds. |
exp | Expiry, also a Unix timestamp in seconds. |
If exp has passed, the token is expired and should be rejected. Because iat and exp are Unix timestamps, a value like 1767225600 corresponds to a specific UTC instant — see the Unix timestamp guide if the numbers look unfamiliar.
Base64URL is not ordinary Base64
JWTs use Base64URL, a variant that replaces + with - and / with _, and omits the = padding. If you paste a JWT into a standard Base64 decoder, those differences can cause errors. The URL-safe alphabet exists so the token can travel in URLs and headers without breaking.
Decoding is not verifying
Anyone can decode a JWT; the payload is merely encoded, not secret. Reading it proves nothing about authenticity. Verifying is a different job: it checks the signature against the server's key and confirms the token was issued by a trusted source and has not been tampered with. A decoder that shows you the claims has not validated them.
This is also why you must never paste a token containing sensitive or live credentials into an untrusted online tool. Decoding reveals everything in the payload, and a valid token can be replayed by whoever holds it until it expires.
Common mistakes
- Treating decode as verify. Seeing valid-looking JSON does not mean the token is genuine.
- Assuming the payload is encrypted. It is only encoded; treat its contents as public.
- Missing the
alg:nonetrap. A token claiming no signature must never be trusted by a server that expects one. - Ignoring expiry. Always check
exp, and allow only small clock skew between systems. - Using the wrong Base64 variant. Standard vs URL-safe encoding is not interchangeable.
Paste a token into our JWT decoder to read the header and payload instantly — decoding only, with no signature verification. To understand how the encoded pieces look in other contexts, see the URL encoding guide and JSON vs CSV.