What's actually inside a JWT, and why decoding one isn't the same as verifying it
A JWT (JSON Web Token, defined in RFC 7519) shows
up constantly in modern auth — session tokens, API credentials, single sign-on. The
eyJhbGci... string looks encrypted. It isn't. Understanding what's actually inside one,
and the difference between reading it and trusting it, matters for anyone debugging auth
issues or reviewing how a system handles them.
Three parts, separated by dots
A JWT is three Base64URL-encoded
segments joined by periods: header.payload.signature. Base64URL is the same idea as
ordinary Base64, swapped to a URL-safe alphabet (- and _ instead of + and /, padding
usually stripped) so the token can sit safely in a URL or an HTTP header without extra
escaping.
The header is a small JSON object naming the signing algorithm and token type:
{"alg": "HS256", "typ": "JWT"}
The payload is the actual content — a JSON object of "claims." Some claim names are standardized by RFC 7519 (though none are strictly required):
iss— issuer, who created the tokensub— subject, who the token is about (commonly a user ID)exp— expiration timeiat— issued-at timenbf— not-before timeaud— audience, who the token is intended for
exp, iat, and nbf are all Unix timestamps — seconds since 1970-01-01 UTC — which is
why a raw payload showing "exp": 1735689600 is hard to sanity-check without converting it
to an actual date first.
The signature is what makes the first two parts trustworthy — a cryptographic signature over the header and payload, computed with a secret (for symmetric algorithms like HS256) or a private key (for asymmetric ones like RS256).
Base64 is not encryption
This is the part that catches people off guard: anyone can decode the header and payload of any JWT with nothing more than a text editor and a Base64 decoder. There's no secret required to read a JWT — only to verify one, or to forge a valid one. Don't put anything in a JWT payload you wouldn't be comfortable showing to whoever holds the token, even if it's never displayed anywhere in your UI.
Decoding vs. verifying — the distinction that matters
Decoding takes the header and payload apart and shows you the JSON. It requires no key of
any kind, and it tells you absolutely nothing about whether the token is legitimate — a
token with a payload of {"sub": "admin", "role": "superuser"} decodes and reads
identically whether it was legitimately issued or hand-crafted by an attacker in five
seconds on jwt.io.
Verifying recomputes the signature using the expected key and checks it matches the signature segment on the token. Only a system that actually performs this check — using a key it controls, not one read out of the token — can trust the claims inside.
This distinction is also the root of a real, historically-exploited vulnerability class:
libraries that let the token itself specify which algorithm to verify with (reading alg
from the header rather than having the server pin it) opened the door to attacks like
switching alg to none (some early library implementations honored this and skipped
verification entirely) or swapping an asymmetric algorithm for a symmetric one and signing
with the public key, which the server may have been treating as a shared secret. Current
guidance across JWT libraries is consistent: the verifying side should specify the expected
algorithm explicitly, never trust the alg field from the token being checked.
What a decoder tool can and can't tell you
A pure decoder — reading header and payload, no key involved — can tell you what a token claims. It cannot tell you whether those claims are true. If you're debugging why a token seems to carry the wrong permissions or an unexpected expiration, a decoder gets you to the actual claim values fast. If the question is "should this system have accepted this token," that's a verification question, and answering it needs the actual signing key and the code path that's supposed to check it.
Sources: RFC 7519 (JSON Web Token); RFC 4648 §5 (Base64URL encoding); RFC 7518 (JSON Web Algorithms, covering HS256/RS256 and related signing algorithms).