1001Ferramentas
๐Ÿช™ Dev

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:

PartContentWhat 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
SignatureSflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cThe 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):

ClaimMeaning
issIssuer โ€” who issued the token
subSubject โ€” the subject, usually the user ID
audAudience โ€” which service the token is valid for
expExpiration โ€” when it stops being valid
nbfNot before โ€” invalid before this instant
iatIssued at โ€” when it was created
jtiJWT 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)
MechanismHMAC with SHA-256RSA signature with SHA-256
KeysA single shared secretA pair: private + public key
Who signsAnyone holding the secretOnly the holder of the private key
Who verifiesAnyone with the same secretAnyone 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:

  1. Check the structure: three dot-separated parts, each a valid Base64URL string.
  2. Read the header and confirm the alg is the one you expect (and not none).
  3. Recompute the signature with the secret/key and compare it to the received one.
  4. Check exp and nbf against the current time.
  5. Verify iss and aud โ€” 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

Keep reading