Skip to content
/>codemaxxed.com
October 20265 min read

How to read a JWT without leaking it

A JSON Web Token looks opaque, which makes people treat it like a password. It isn't. The contents are base64url, readable by anyone holding the string. Knowing that changes how you store it, where you paste it, and what you assume when a request fails.


Three segments, one of which is a signature

A JWT is header.payload.signature. The header names the signing algorithm, the payload holds claims, and the signature proves the first two were issued by whoever holds the key. Header and payload are base64url — an encoding, not encryption.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiI4MjQxIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzYxMjY3NjAwfQ
.c2lnbmF0dXJl

Decoding is not verification

Anyone can produce a token with role: admin in the payload. It is only trustworthy if the signature checks out against a key your server controls. That is why browser-side decoding is fine for debugging and useless for authorization: the browser can read the claims but cannot prove them.

There is a related trap in the header itself. Never let the token choose its own verification algorithm. Accepting alg: none, or trusting an RS256 token that claims to be HS256, are the two classic ways JWT libraries have been broken. Pin the algorithm on the server.

The claims worth checking first

  • exp — expiry, in seconds since the epoch. A millisecond value here is a common bug that produces tokens valid for tens of thousands of years.
  • iat — issued at. Useful for spotting a token that was minted long before it was used.
  • nbf — not before. If this is in the future, a correct server will reject the token even though it hasn't expired.
  • sub — the subject. Usually a user ID, and the claim your app actually cares about.
  • aud and iss — audience and issuer. A valid signature from the wrong service is still the wrong token.

Why pasting a token into a random site is risky

A JWT is a bearer credential: whoever holds it can use it until it expires. Sending one to a server-side decoder hands a live session to that server, and possibly to its logs. If you need to inspect a token, use a tool that decodes locally in the browser, and prefer a short-lived development token over a production one.

For storage, the trade-off is between XSS and CSRF. A token in localStorage is readable by any script that gets injected into the page; a token in an httpOnly cookie is not, but it needs CSRF protection. Most teams are better served by httpOnly cookies plus a strict Content Security Policy.

Decode the header and payload, see the expiry in plain English, and keep the token in your browser.

Open the JWT decoder