Every time your application talks to an API that uses token-based auth, a JSON Web Token (JWT) travels with the request. On the surface it's an opaque string of letters, dots, and equals signs — but each token is really three independent segments that any developer can read in seconds once they know what to look for.
Anatomy of a JWT
A JWT is built from three dot-separated parts: the header, the payload, and the signature. Each part is base64url-encoded JSON, so decoding them is purely a matter of un-encoding the text — no secrets required for the first two segments.
- Header — describes how the token was signed, e.g. {"alg":"HS256","typ":"JWT"}.
- Payload — the claims: who the token is for (sub), the audience (aud), the issuer (iss), and when it expires (exp).
- Signature — a cryptographic digest that proves the token hasn't been tampered with.
Never trust the payload alone
Anyone can decode the payload — encoding is not encryption. Always verify the signature server-side with the correct secret or public key before trusting any claim.
Reading the claims you actually care about
In practice, the fields that matter day-to-day are the expiration time and the subject. exp is a Unix timestamp; if it's in the past, the token is expired. sub identifies the user, and aud tells you which audience the token was minted for — mismatches here are a common source of confusing 401s.
Instead of base64-decoding each segment by hand and converting Unix timestamps in your head, paste the token into ForgePlug's JWT Decoder. It splits the segments, renders the claims as readable JSON, and shows a live countdown of how much validity remains — including an expired-state warning the moment the token lapses.
Decode a token in one paste
Paste any JWT — including third-party tokens — and see header, payload, expiration, and signature instantly. Everything runs locally in your browser.
Open JWT DecoderHS256 vs RS256 — why the signing algorithm matters
The header's alg field tells you how the signature was produced, and it changes who can verify a token. HS256 is symmetric — the same secret both signs and verifies, so only the issuing server (which holds that secret) can check a token is genuine. RS256 is asymmetric — the issuer signs with a private key, but anyone holding the matching public key can verify it, which is why RS256 shows up constantly in single-sign-on and third-party API scenarios where the verifier isn't the issuer.
This distinction explains a specific attack you'll see referenced in security write-ups: an attacker who notices a server accepts both HS256 and RS256 tokens can sometimes take a public RS256 key, resign a forged token as HS256 using that public key as the "secret," and get it accepted — because the server treats the public key as trusted material for symmetric verification. Well-configured JWT libraries pin the expected algorithm per key and refuse a mismatch specifically to close this off; it's worth confirming your own backend does the same rather than trusting the alg field in an incoming token.
Decoding one by hand, without a tool
It's worth doing once so the format stops feeling like magic. Split the token on its two dots to get three strings. The first two are base64url — not quite standard base64, since it swaps + and / for - and _ and drops padding — so a plain base64 decoder will choke on real-world tokens until you restore the padding and swap those two characters back. Decode each of the first two segments and you get two JSON objects: the header and the payload. The third segment, the signature, is binary and isn't meant to be human-readable at all — it only means something when recomputed with the correct secret or key and compared byte-for-byte against what's on the token.
Common pitfalls
- Expired tokens — the exp claim passed, but your client never refreshed. Check the countdown before debugging anything else.
- Malformed input — a token missing a segment, or with non-URL-safe characters, will fail to parse entirely.
- Wrong audience — the token is valid but was issued for a different aud, and the API rejects it.
- Clock skew — a token that says "not valid until" (nbf) a few seconds in the future can get rejected by a server whose clock is running slightly behind the one that issued it; this shows up as an intermittent, hard-to-reproduce failure rather than a consistent one.
Reading JWTs is a skill every backend and frontend developer hits eventually. Once you can decode a token in a single paste — and understand why the signature segment is the only part that actually protects you — debugging auth flows stops being guesswork and starts being a quick two-step check: is it expired, and is it actually signed by who it claims.
