Technology

What a JWT is, what is inside it and why decoding it is not validating it

Anatomy of a JSON Web Token (header, payload and signature), which claims it carries, how to read it, the common security mistakes and where to store it.

A JWT (JSON Web Token, RFC 7519) is a text string with three dot-separated parts, header.payload.signature, that carries claims about a user or a session in a way that lets the receiver check that nobody has modified them. The first two parts are Base64URL-encoded JSON: anyone can read them. The third is a signature that only the holder of the key can produce. That is why decoding a JWT is not validating it: reading the content is trivial; trusting it requires verifying the signature, the expiry and the issuer.

This article walks through the anatomy of a token, the usual claims, how to inspect one, the classic security mistakes and where to store it in a web application.

Anatomy of a token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0IiwibmFtZSI6IkFpbXJhbiIsImlhdCI6MTc5MTI4MDAwMCwiZXhwIjoxNzkxMjgzNjAwfQ.<signature>
  1. Header ({"alg":"HS256","typ":"JWT"}): the signing algorithm and the token type.
  2. Payload ({"sub":"1234","name":"Aimran","iat":1791280000,"exp":1791283600}): the claims.
  3. Signature: the result of signing base64url(header) + "." + base64url(payload) with the algorithm in the header. With HS256 it is an HMAC-SHA256 with a shared secret key; with RS256 or ES256 it is an asymmetric signature made with a private key and verified with the public key.

The encoding is Base64URL (a Base64 variant with - and _ instead of + and /, without = padding), covered in what Base64 is. It is not encryption: the payload can be read with one line of code.

The usual claims

Claim Name Purpose
iss Issuer Who issued the token (your authentication server).
sub Subject Who it is about (the user identifier).
aud Audience Who it is for (the API that should accept it).
exp Expiration Unix time after which it is not valid.
nbf Not before Unix time before which it is not yet valid.
iat Issued at When it was issued.
jti JWT ID Unique identifier, useful for revocation.

All of them are optional according to the RFC, but exp should always be present: a token without expiry is valid forever if it leaks. You can add your own claims (role, plan), with one rule: never sensitive data, because the payload is public to whoever holds the token.

How to inspect a JWT

To see what a token carries you only need to decode the first two parts. The JWT decoder on AIMRAN Tools shows header and payload, turns iat, exp and nbf into readable dates and tells you whether the token is expired or not yet valid, all in the browser without sending the token to any server. If you also paste the secret, it verifies the HMAC signature. In Node.js, without libraries:

const [header, payload] = token.split('.');
const decode = (part) => JSON.parse(Buffer.from(part, 'base64url').toString('utf8'));
console.log(decode(header), decode(payload));

That code reads, it does not validate. To validate, use an established library (jose or jsonwebtoken in Node; PyJWT in Python) that checks the signature with the algorithm you expect, the expiry and the issuer.

Security mistakes that keep coming back

RFC 8725, the official best practices, covers most of them:

  1. Trusting the payload without verifying the signature. Anyone can forge a token with "role":"admin". If your API does not verify the signature, it has just given away permissions.
  2. Accepting whatever algorithm the header says. The classic alg: none attack sends an unsigned token and hopes the server accepts it. The library must verify only the algorithms you configure.
  3. HS256/RS256 confusion. If the server uses RS256 (public key) and also accepts HS256, an attacker can sign with the public key as if it were the HMAC secret. Same fix: a closed list of algorithms.
  4. Weak HMAC secrets. A short secret can be brute-forced offline, because the attacker holds the token. Use random secrets of at least 256 bits.
  5. Eternal tokens. No exp, or expiries of months. The usual pattern: access tokens lasting minutes plus a refresh token to renew them.
  6. Sensitive data in the payload. Emails, ID numbers, addresses: the payload is not encrypted. If you need confidentiality, JWE (encrypted tokens) exists, but it is rarely necessary.

Where to store the token in the browser

Two options, with different trade-offs:

  • HttpOnly; Secure; SameSite cookie: JavaScript cannot read it, so an XSS cannot steal it; the browser sends it automatically; you need CSRF protection (SameSite=Lax or Strict covers most cases). This is the usual recommendation for classic web applications.
  • localStorage or memory: any script on the page can read it, so an XSS compromises it completely. It makes sense only for clients that cannot use cookies (native apps) or when the API lives on another domain and the token stays in memory for the life of the tab.

In both cases, serving the site with a strict Content-Security-Policy reduces the XSS risk, which is the real threat behind this debate.

JWT versus classic sessions

A JWT lets the API validate identity without querying a database on every request: all the information travels in the token. That advantage has a cost: a token cannot be revoked before it expires unless you keep a revocation list (which brings the database query back). For an application with a single server, a traditional session (opaque identifier in a cookie, data on the server) is simpler and easier to invalidate. JWTs shine when several services must accept the same identity without sharing a session store.

Conclusion

A JWT is three Base64URL blocks: header, payload and signature. Anyone can read the first two; only the signature, verified with the right algorithm and the right key, lets you trust them. Always add exp, limit the accepted algorithms, keep sensitive data out of the payload and store it in an HttpOnly cookie when you can. And when you want to know what a token carries, decode it without fear: that part really is free.

Sources and references

  1. RFC 7519: JSON Web Token (JWT) rfc-editor.org
  2. RFC 7515: JSON Web Signature (JWS) rfc-editor.org
  3. RFC 8725: JSON Web Token Best Current Practices rfc-editor.org
  4. OWASP Cheat Sheet: JSON Web Token for Java cheatsheetseries.owasp.org
  5. MDN: Using HTTP cookies developer.mozilla.org

Related tools

Herramientas gratuitas de AIMRAN Tools que funcionan en tu navegador, sin registro.

Ver todas las herramientas
  • JWT decoder

    Reads a token’s header, payload and expiry and verifies HMAC signatures with your secret, all in the browser.

Articles in Technology