Skip to main content
ToolsHub
6 min read

Understanding JWT Tokens: Structure and Pitfalls

A clear guide to JSON Web Tokens: the header.payload.signature structure, base64url encoding, standard claims, and the security mistakes that bite teams.

What a JWT Actually Is

A JSON Web Token (JWT) is a compact, self-contained way to carry claims between two parties. You see them most often as the bearer token an API sends back after login, which the client then attaches to every subsequent request. The defining feature of a JWT is that it is signed, not encrypted. Anyone who holds the token can read its contents — the data is merely encoded, not hidden. What the signature provides is integrity: a server can verify the token was issued by a trusted party and has not been tampered with. This is why you should never put secrets like passwords inside a JWT payload. To inspect a token safely, paste it into the JWT decoder. It decodes the parts locally in your browser, so the token never travels to a server — but as a habit, avoid pasting live production tokens into any tool you do not control. This read-but-verify distinction is the single most important idea about JWTs: the contents are public, but trust comes only from checking the signature. Almost every mistake covered later traces back to forgetting that one point.

The Three Parts: header.payload.signature

A JWT is three base64url strings joined by dots: header.payload.signature. The header is a small JSON object describing the token type and the signing algorithm, for example { "alg": "HS256", "typ": "JWT" }. The payload holds the claims — the actual data, such as who the user is and when the token expires. The signature is computed over the encoded header and payload using the algorithm named in the header. For HMAC algorithms it uses a shared secret; for RSA or ECDSA it uses a private key, and anyone can verify it with the matching public key. The first two parts are just base64url-encoded JSON. That encoding is a URL-safe variant of base64 — it swaps "+" and "/" for "-" and "_" and drops padding — so a token survives being placed in a URL or header. If you want to see how that encoding works on arbitrary data, experiment with the base64 encoder.

Standard Claims You Should Know

The JWT specification reserves a set of short claim names so different systems interoperate. The most important ones are: iss (issuer) — who created and signed the token. sub (subject) — who the token is about, usually a user ID. aud (audience) — who the token is intended for; a recipient should reject tokens not meant for it. exp (expiration) — a Unix timestamp after which the token must be rejected. Short lifetimes limit the damage of a leaked token. iat (issued at) and nbf (not before) — when the token was created and the earliest time it is valid. Validating exp on every request is non-negotiable; a surprising number of breaches come from servers that decode a token but never check whether it has expired. The signature itself is an HMAC or public-key operation — if you want to understand the keyed-hash side, the HMAC generator shows how a secret and a message combine into a verifiable tag.

Common Pitfalls That Bite Teams

JWTs are easy to use and easy to misuse. Watch for these traps. The alg=none attack. The spec defines a "none" algorithm meaning "unsigned." If a server trusts the algorithm field in the header without enforcing an expected algorithm, an attacker can strip the signature, set alg to none, and forge any payload. Always pin the accepted algorithm server-side and reject anything else. Confusing signing with encryption. Because the payload is readable by anyone, never store passwords, full card numbers, or other secrets in it. Storing tokens in localStorage. Tokens in localStorage are readable by any JavaScript on the page, so a single cross-site scripting flaw leaks them. HttpOnly cookies are generally safer for browser apps, paired with CSRF protection. Forgetting to verify the signature. Decoding a token is trivial; verifying it requires the key. Never trust claims from a token whose signature you have not checked. A safe inspection routine looks like this: 1. Decode the token to read the header and payload. 2. Confirm the algorithm matches what your server expects. 3. Verify the signature with the correct secret or public key. 4. Check exp, nbf, and aud before trusting any claim.

Frequently Asked Questions

Is a JWT encrypted?

No. A standard JWT is signed, not encrypted, so anyone holding it can read the header and payload. The signature only proves the token has not been altered. Never place secrets in the payload.

What is the alg=none vulnerability?

It is an attack where a token sets its algorithm to "none" to claim it is unsigned. A server that does not enforce an expected algorithm may accept the forged token. Always pin the accepted algorithm server-side.

Where should I store a JWT in a browser app?

An HttpOnly cookie is usually safer than localStorage because JavaScript cannot read it, which limits the impact of cross-site scripting. Pair cookies with CSRF protection for session-style auth.

Is it safe to decode a token in an online tool?

The JWT decoder here runs in your browser, so the token is not uploaded. Even so, treat production tokens as live credentials and avoid pasting them into tools you do not fully trust.