How JWTs Work: Header, Payload, Signature, and What a Decoder Can't Tell You
A JWT looks like a long, unreadable string of gibberish — three chunks separated by dots. In fact two of those three chunks aren't secret or encrypted at all; they're just JSON, written out in a URL-safe text encoding. Understanding that split — what's openly readable versus what actually needs a secret key — is most of what you need to use JWTs safely.
The three parts
A JWT is always exactly three dot-separated parts, in order: a header, a payload, and a signature — header.payload.signature. The JWT Decoder checks for exactly this shape first; a string with more or fewer than three parts isn't a JWT at all and is rejected immediately, before any decoding is attempted.
Header and payload: just Base64URL-encoded JSON
The header and payload aren't a special or proprietary format — each is a plain JSON object, encoded with Base64URL, the URL-safe variant of Base64. That means decoding them requires no secret whatsoever: reverse the Base64URL alphabet back to standard Base64, decode it, and you have the original JSON — exactly what the JWT Decoder does, and exactly what any JWT decoding library or website does. The header typically states the signing algorithm and token type; the payload carries the actual claims — who the token represents, when it was issued, when it expires, and whatever else the issuer chose to include.
Because this decoding needs no key, anyone who has the token can read every claim inside it. A JWT is not a safe place for information that needs to stay confidential from whoever might see the token — data inside it should be treated as visible, not secret.
Standard time claims: exp, iat, nbf
Three commonly used claims hold Unix timestamps in seconds: iat (issued at), nbf (not valid before), and exp (expires at). The JWT Decoder recognizes these three specifically and shows the human-readable date alongside the raw number, since a bare number like 1700000000 means little on its own. These are ordinary Unix timestamps — the same format covered in the Unix timestamps guide, including the seconds-vs-milliseconds distinction that occasionally trips up a hand-built JWT.
The signature: what a decoder can't tell you
The third part, the signature, is what actually proves the token wasn't tampered with — and it's also the part a plain decoder never touches. Verifying it means recomputing the signature using the secret or public key that produced it and confirming the two match; the JWT Decoder never asks for a key and never performs this check, so it only ever shows you the header and payload's contents, nothing about whether they're genuine.
This has a concrete, easy-to-miss consequence: a decoded token is not proof that it's valid, unexpired-by-policy, or issued by who it claims to be. Anyone can construct a JWT with any header and payload they like and a signature that won't verify — decoding it looks identical to decoding a genuine one, because decoding never checks the signature at all. Only an application that verifies the signature with the correct key can actually trust a token's contents.
Checking expiry, correctly
To check whether a token has expired, compare its exp claim — in seconds — against the current time in seconds, not milliseconds (JavaScript's Date.now() returns milliseconds, so it needs dividing by 1000 first). A token past its exp should generally be treated as invalid by anything relying on it, but remember this is a claim inside the payload, not something a decoder verifies against a clock automatically — the tool shows you what the token claims, and it's up to you (or your application's JWT library) to compare it against the actual current time.
Common pitfalls
- Treating decoding as validation. A token that decodes cleanly into readable JSON tells you the format is well-formed — nothing about whether it's genuine, current, or intended for your application.
- Trusting claims a server hasn't itself verified. If a token is decoded client-side purely for display (showing a username from the payload, say), that's fine — but any decision that matters (granting access, authorizing an action) needs the signature actually verified, generally on a server that holds the key.
- Pasting real, production tokens into any online tool — this one included. Since a JWT's payload is fully readable to anyone with the string, treat a live token with the same care as a password: prefer a test or expired token when exploring what a JWT looks like decoded.
The header and payload being visible JSON also means they follow ordinary JSON rules — formatting the raw decoded output through the JSON Formatter can make a payload with many claims easier to read.
Try it yourself
JWT DecoderDecode a JSON Web Token's header and payload without verifying the signature.Related guides
Unix Timestamps and Time Zones: Seconds vs Milliseconds, UTC, and the Year 2038 Problem
Seconds versus milliseconds, UTC versus local time, and the year 2038 limit, plus the mistakes that produce wrong dates.
Related tool: Unix Timestamp Converter
Base64 Explained: What It Is, Why It's 33% Larger, and Base64URL vs Standard
How Base64 works, why it adds about a third to the size, why it isn't encryption, and how Base64URL differs.
Related tool: Base64 Encoder & Decoder