Inside a JWT: The Anatomy of a Token
The three parts of a JWT, what goes (and never should go) in the payload, how the signature protects it, and why decoding is not trusting.
Updated on June 30, 2026 ยท 7 min read
The three parts of a JWT (header.payload.signature)
A JWT โ JSON Web Token, defined in RFC 7519 โ is one of those long, scrambled strings that show up in the Authorization: Bearer ... header of nearly every modern API. The look is intimidating; the structure is not. It is three blocks separated by dots. Look closely and you can spot the two dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Each part is a chunk of JSON encoded in Base64URL (the Base64 variant that swaps + and / for - and _ and drops the padding, so it survives inside a URL). The three parts are:
| Part | Content | What it does |
|---|---|---|
| Header | {"alg":"HS256","typ":"JWT"} | States the signing algorithm and type |
| Payload | {"sub":"1234567890","name":"John Doe","iat":1516239022} | The data (claims) the token carries |
| Signature | SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c | The cryptographic proof the token is authentic |
That first block, eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9, is just the Base64URL of {"alg":"HS256","typ":"JWT"} โ every HS256 JWT begins with exactly those characters, because the header is always the same. Paste the whole token into the JWT Decoder and it splits and decodes all three parts instantly, showing the readable JSON for each.
What goes โ and what NEVER goes โ in the payload
Here is the misunderstanding that leaks the most data: the payload is not encrypted, only encoded. Base64URL is reversible by anyone, with no key at all. Whoever intercepts the token reads its contents in seconds. Hence the golden rule:
Never put in a JWT payload: a password, a card number, a national ID, a token for another system, an API key, or anything you would not print on a billboard. The payload is public to whoever holds the token.
What should go in are the claims โ statements about the user and about the token itself. RFC 7519 reserves seven short, standardized names (the registered claims):
| Claim | Meaning |
|---|---|
iss | Issuer โ who issued the token |
sub | Subject โ the subject, usually the user ID |
aud | Audience โ which service the token is valid for |
exp | Expiration โ when it stops being valid |
nbf | Not before โ invalid before this instant |
iat | Issued at โ when it was created |
jti | JWT ID โ a unique identifier, handy for revocation |
On top of these you can add your own claims (role, plan, email) โ just remember everything is visible. Want to see the fields of a real token of yours? The JWT Token Decoder lists every claim with its value and automatically turns exp and iat (which are Unix timestamps) into readable dates.
How the signature protects the token
If anyone can read the payload, what stops a user from changing "role":"user" to "role":"admin" and granting themselves superpowers? The answer is the third part: the signature.
In HS256, the signature is computed like this:
HMAC-SHA256( base64url(header) + "." + base64url(payload), secret )
The server takes the two already-encoded parts, joins them with a dot, and produces an HMAC-SHA256 using a secret key that only it knows. The result is the third part. When the token comes back on a request, the server redoes exactly that calculation and compares: if the client changed a single character of the header or payload, the recomputed HMAC will not match the signature that was sent, and the token is rejected.
All the security rests on the secret. Because the attacker does not know it, they can alter the payload but cannot forge the matching signature. That is why the token's integrity does not depend on hiding the data โ it depends on the signature being impossible to fake. You can build a token from scratch, choose the claims, and watch the signature being generated step by step in the JWT Builder (HS256); change one character of the secret and watch the signature change completely.
HS256 vs RS256
The header's alg field decides how the signature is made. The two most common algorithms solve the same problem in opposite ways:
| HS256 (symmetric) | RS256 (asymmetric) | |
|---|---|---|
| Mechanism | HMAC with SHA-256 | RSA signature with SHA-256 |
| Keys | A single shared secret | A pair: private + public key |
| Who signs | Anyone holding the secret | Only the holder of the private key |
| Who verifies | Anyone with the same secret | Anyone with the public key |
With HS256, whoever can verify can also forge, because signing and verifying use the same key. That is perfect when the same service issues and validates the tokens โ a monolith, say. RS256 splits the roles: the authentication server keeps the private key and signs; any microservice can validate using only the public key (usually published at a JWKS endpoint), without ever being able to mint a fake token. That is why RS256 dominates distributed architectures, OAuth, and OpenID Connect.
A classic security caveat: the server must pin the expected algorithm. Old libraries accepted "alg":"none" (an unsigned token) or were fooled by an algorithm-confusion attack, in which the attacker feeds the RS256 public key while passing it off as an HS256 secret. Never blindly trust the alg that arrives inside the token itself.
Expiration, claims and validation
The exp claim is a Unix timestamp โ the number of seconds since January 1, 1970 in UTC, not milliseconds. In our example, iat is 1516239022, which is January 18, 2018. If the token were valid for 15 minutes, exp would be 1516239022 + 900 = 1516239922. The server compares that value against the current clock and rejects the token once the present time has passed exp (usually with a small leeway of a few seconds for clock skew).
Validating a JWT for real is a sequence, not a single step:
- Check the structure: three dot-separated parts, each a valid Base64URL string.
- Read the header and confirm the
algis the one you expect (and notnone). - Recompute the signature with the secret/key and compare it to the received one.
- Check
expandnbfagainst the current time. - Verify
issandaudโ was the token issued by someone you trust and meant for this service?
The first step, the structural one, you can inspect on its own with the JWT Structure Validator, which checks that all three parts exist and that each decodes to well-formed JSON โ handy for quickly spotting a token that arrived truncated or corrupted. Because JWTs are stateless by default (the server stores nothing), the usual way to "revoke" a token is to give it a short life โ minutes โ and renew it with a refresh token.
Decoding is not the same as trusting
This is the most important lesson and the most ignored. Decoding a JWT is trivial; trusting it requires verifying the signature. Opening the payload with Base64 and reading "role":"admin" proves absolutely nothing โ anyone can produce a string with that content. What establishes trust is the signature step, and only the holder of the secret (HS256) or the public key (RS256) can run it.
The practical consequence applies to both backend and frontend:
- The server must verify the signature on every protected request before using any claim. Decoding and trusting without verifying is a serious security flaw.
- The client (app, SPA) may decode the payload to, say, show the user's name โ but must never make security decisions based on it, because the browser cannot safely verify the signature.
Tools that "open" a JWT โ including the ones on this site โ only do the Base64 decoding. They show you the contents; they do not certify that those contents are legitimate. Use them to debug, understand, and inspect tokens, and let the cryptographic verification happen on the server, where the secret lives.
Frequently asked questions
Is a JWT encrypted?
No, not by default. A signed JWT (a JWS) is merely Base64URL-encoded โ anyone can read the payload. There is a separate format, JWE (JSON Web Encryption), that does encrypt the contents, but it is far less common. When in doubt, treat the payload of an ordinary JWT as public.
Can I trust the data I read when I decode a token?
Only after verifying the signature. Decoding shows the contents, but it does not prove the token is authentic or unaltered. Without checking the signature with the secret or the public key, any claim could have been forged.
What is the difference between HS256 and RS256?
HS256 uses a single shared secret to sign and verify โ simple, ideal when the same service does both. RS256 uses a key pair: the private key signs and the public key verifies, letting third parties validate a token without being able to issue one. RS256 is the standard in distributed systems and OpenID Connect.
How do I invalidate a JWT before it expires?
Since the token is stateless, you do not really "delete" it. The usual approaches are: keep a revocation list (denylist) keyed by jti, use short-lived access tokens with refresh tokens, or rotate the signing secret (which invalidates every token at once). Short life plus refresh is the most common strategy.
Why does my token have only two parts instead of three?
It was probably truncated somewhere (a clipped HTTP header, an incomplete copy) or it is an "unsecured" JWT with alg:none and an empty signature. Run the token through the JWT Structure Validator to confirm whether all three parts are present and well-formed.
Tools mentioned in this guide
JWT Decoder
Decode and inspect JWT (JSON Web Tokens). View the header, payload and verify expiration. Processed 100% in the browser โ the token never leaves your device.
JWT Token Decoder
Decode JWT (JSON Web Tokens) and view the header, payload and signature. Automatically detects expiration. Useful for debugging API authentication.
JWT Builder (HS256)
Build a JWT by filling in header, payload and secret. HS256 signature computed in the browser via SubtleCrypto.
JWT Structure Validator
Verify whether a JWT has valid structure (3 segments), header and payload decodable in base64url, and shows exp, iat, nbf and any claims. Everything in your browser.
Keep reading
JSON in Practice: Format, Validate and Convert Without the Headache
JSON syntax in five minutes, the most common errors, pretty-print vs minify, and how to convert to CSV, YAML and XML.
7 min read
Regular Expressions From Scratch: A Practical Beginner's Guide
What a regex is and where it lives, the essential metacharacters, groups and captures, ready-made patterns, and the mistakes that make regex slow.
9 min read