JWT Explained: What's Actually Inside a JSON Web Token
By ToolZoneX Team
•
August 2026
A JSON Web Token looks like a wall of gibberish — eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NSJ9.abc123 — but it's not encrypted. It's just three base64url-encoded JSON objects stuck together with dots. Anyone can decode a JWT and read its contents without any secret key at all. That distinction — encoded, not encrypted — is the single most important thing to understand about how JWTs actually work.
The three parts
Split the token on its dots and you get three segments, each independently base64url-decodable:
- Header — a small JSON object naming the signing algorithm (e.g.
HS256,RS256) and token type. Nothing sensitive here, just metadata about how to verify it. - Payload — the actual data, called claims: things like a user ID (
sub), an expiry timestamp (exp), an issuer (iss), and whatever custom fields the issuing service adds (roles, permissions, session data). This is plain JSON, base64-encoded for transport — not hidden. - Signature — the only part that actually requires a secret. It's a cryptographic signature over the header and payload, computed with a key only the issuing server holds. This is what makes the token tamper-evident: change one character of the payload and the signature no longer matches.
Encoded, not encrypted — why it matters
Because the payload is just base64, never put secrets in it — passwords, API keys, or anything you wouldn't want a user to read directly, since any JWT sitting in a browser's localStorage or a network request can be decoded by anyone in a few seconds. What the signature does guarantee is integrity: if a client tries to edit the payload to escalate their own role or extend their own expiry, the signature check fails on the server and the token is rejected.
The mistake that keeps showing up: not checking exp
A shockingly common implementation bug is verifying a JWT's signature but forgetting to check whether it has actually expired. The signature only proves the token wasn't tampered with — it says nothing about whether it's still valid. A correct verification step checks the signatureand the exp claim (and often nbf/"not before" andiss/issuer) before trusting anything in the payload. Most JWT libraries do this automatically if you use their verify function — the risk shows up when someone hand-rolls decoding logic and skips it.
A worked example
A decoded payload might look like:
{
"sub": "user_12345",
"role": "editor",
"iat": 1755878400,
"exp": 1755882000
}iat (issued at) and exp (expiry) are Unix timestamps. A server checks the current time against exp on every request — once it's passed, the token is rejected regardless of how valid its signature still is.
Try it yourself
Paste any JWT into the JWT Decoder to see its header and payload broken out instantly — useful for debugging an auth flow or just understanding what a third-party API is actually putting in the tokens it hands you. It decodes only, and never verifies or transmits the signature, so it's safe to use on real tokens while debugging locally.
Related Tools
JWT Decoder
Paste any JWT and see its header and payload decoded into readable JSON instantly.
