Profile    Mohammed Shiroz Status   Loading  
Logo
Share This
Back to blog
Filter by:
Tags
//Article title

JWT Explained: What's Inside the Token and What Can Go Wrong

About Post

Here's a quick experiment. Take a JWT from any app you're building, paste it into a decoder, and look at the result. No secret key, no password. You can read everything inside it.

The first time developers see this, there's often a small moment of panic. "Wait, isn't it encrypted?" No. And understanding why it doesn't need to be (and when that becomes a problem) is most of what you need to know to use JWTs safely.

Three parts and two dots

A JSON Web Token looks like a random blob, but it's three pieces joined with dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9      <- header
.
eyJzdWIiOiI0MiIsInJvbGUiOiJzdGFmZiIsImV4cCI6MTczOTYxMDAwMH0   <- payload
.
(signature bytes, also base64url)          <- signature

(In a real token the three parts sit on one line: header.payload.signature.)

Decode the first two parts and you get plain JSON:

// header
{ "alg": "HS256", "typ": "JWT" }

// payload (the "claims")
{ "sub": "42", "role": "staff", "exp": 1739610000 }
  • Header: which algorithm was used to sign the token.
  • Payload: the claims. Who the user is (sub), when the token expires (exp, a Unix timestamp), and whatever else you put in.
  • Signature: a cryptographic signature of the header and payload, made with a key only the server knows.

Base64 is not encryption

The header and payload are only base64url-encoded. Encoding is like writing a message in a different alphabet: anyone who knows the alphabet can read it. There's no key involved.

What the signature gives you is integrity, not secrecy. Think of a sealed glass box: everyone can see what's inside, but nobody can change it without breaking the seal. If a user edits the payload to say "role": "admin", the signature no longer matches and the server rejects the token.

So the rule is simple: never put secrets in a JWT payload. No passwords, no personal data you wouldn't show the user, no internal details. A user ID and a role are fine. A national ID number is not.

(There is an encrypted variant, JWE, but when people say "JWT" they almost always mean the signed kind, JWS.)

How the server checks a token

On each request the server:

  1. Splits the token into its three parts.
  2. Recomputes the signature over the header and payload with its own key.
  3. Compares it with the signature in the token.
  4. Checks the claims: is exp in the future? Is the issuer and audience what we expect?

No database lookup needed. That's the big selling point of JWTs: any server holding the key can verify a token on its own, which is handy across services. It's also the root of their biggest weakness.

The revocation problem

A user logs out. Or you ban them. Or their phone is stolen. With a session stored on the server, you delete the session and they're out instantly.

With a JWT, the token is valid until it expires, because the whole point was that the server doesn't check anything stored. You've handed out a signed permission slip and you can't take it back.

The common ways teams deal with it:

  • Short-lived access tokens (minutes, not days) plus a refresh token that is stored on the server and can be revoked.
  • Refresh token rotation: every refresh issues a new refresh token and invalidates the old one, so a stolen one is quickly useless.
  • A denylist of revoked token IDs (the jti claim) checked on each request. It works, but notice you've just reintroduced a lookup on every request, which is what JWTs were meant to avoid.

Which leads to an honest question worth asking: for a single web app talking to its own backend, do you need JWTs at all? A plain server-side session or an opaque token stored in the database (which is what Laravel Sanctum's API tokens are) is often simpler and revocable by design.

The "alg: none" story

The JWT standard includes an algorithm called none, meaning "this token isn't signed". Around 2015, security researchers showed that several popular JWT libraries would trust the alg value from the token's own header. An attacker could take a token, change the payload, set "alg": "none", remove the signature, and some servers would accept it.

A related trick was algorithm confusion: telling a server that expected an RSA signature to verify with HMAC instead, using the public key as the HMAC secret.

Libraries have long since been fixed, but the lesson still matters: the server decides the algorithm, never the token. Always configure your library with the exact algorithm you expect.

Verification checklist: pin the algorithm, verify the signature, check exp, check issuer and audience, and keep the signing key out of your repository. Decoding a token is not the same as verifying it.

Where to store it in the browser

This one starts arguments, so here's the trade-off plainly:

  • localStorage: easy, but any JavaScript on the page can read it. One XSS bug and the token is gone.
  • httpOnly cookie: JavaScript can't read it, which protects it from XSS theft. But the browser sends it automatically, so you need CSRF protection and sensible SameSite settings.

For web apps I lean towards httpOnly, Secure, SameSite cookies. In a mobile app, the platform's secure storage (Keychain on iOS, Keystore on Android, or expo-secure-store in Expo) is the right home.

If you remember one thing

A JWT is a signed note, not a locked box. Anyone can read it, nobody can forge it, and once it's out you can't easily take it back. Keep the payload boring, keep the lifetime short, and let the server, not the token, decide how it's verified.

Do you use JWTs for your own web apps, or have you gone back to sessions? I'd like to hear what tipped the decision.

Comments (0)
Leave your review

Thanks for your valuable comments. Your comments has been updated and appreciate your getting in touch...

01. About Shiroz

Mohammed Shiroz

Hi, I'm Mohammed Shiroz, a software engineer and AI enthusiast from Sri Lanka who turns ideas into intelligent, real-world solutions. With over 9 years of hands-on experience, I currently lead real estate ERP development at Kate Group, a...

03.My Projects

04. Categories

Ready To order Your Project ?

Get in Touch
Close