What is a JWT — and why the server doesn't remember you but lets you in anyway

Strange thing: you log into an app once, and it "remembers" you on every page after. You'd assume the server wrote down "this person is logged in" somewhere. But usually — no. The server stores nothing about you. It re-checks a pass you show it, every single time.
That pass is the JWT (JSON Web Token). And it hides one non-obvious detail that trips up beginners: anyone can read what's inside the token. Let's unpack how it works and why it's still safe.
What a JWT means in plain words
Picture a festival. At the entrance they put a wristband on you. After that you roam freely, and security in each zone just glances at the band — they don't phone the box office to check whether you bought a ticket. The wristband itself is the proof.
A JWT is the same wristband, but digital. When you log in, the server hands you a token. The browser stores it and attaches it to every request. The server looks at the token, confirms it's genuine, and lets you through. It doesn't need to hit a database to figure out "who is this." The answer is already in the token.
This is called stateless — "no state." The server keeps no session logbook. All the needed info travels with you.
Three parts of one token
A JWT looks like a long string with two dots: xxxxx.yyyyy.zzzzz. That's three glued-together parts.
- Header — the technical cap: which signing algorithm is used.
- Payload — the useful filling: who you are (user id), what permissions you have, until when the token is valid. This is "what's written on the wristband."
- Signature — the seal. The server takes the first two parts plus its secret key, runs them through the algorithm, and gets a signature. It's a stamp you can't forge without knowing the secret.
When the token comes back, the server recomputes the signature with its secret and compares. Match — the token is genuine and untouched. No match — into the trash. That secret key lives not in code but in the server's environment variables — it must never be shown to anyone.
The main trap: nothing inside is encrypted
Now — the detail that breaks intuition.
The payload isn't encrypted. It's just base64-encoded — which is not encryption but a way of writing that unfolds back with a single line. Anyone holding your token can read everything inside: your id, email, role. Try it yourself — paste a token into jwt.io and you'll see the contents in plain text.
Hence the iron rule: never put secrets in a JWT — no passwords, card numbers, or private data. Only put in things you wouldn't mind showing.
"But if the payload is open, why can't it be forged?" — You can read it, but you can't rewrite it. Change a single character inside and the signature stops matching, because you don't have the secret. The signature protects against tampering, not reading.
Why this matters to you as an app builder
The big win of stateless tokens is scalability.
Imagine you have not one server but five — behind a load balancer that tosses requests to whichever. If the server kept sessions in its own memory, switching to a neighbor server would log you out — it doesn't know you. With JWTs there's no such problem: the token travels with you, and any server verifies it with its secret. No shared session database, no extra coupling.
There's an honest downside too: since the server stores nothing, revoking one specific token before it expires is hard — it stays valid until it ages out. So JWTs are made short-lived (minutes to hours) and refreshed with a separate refresh token.
In practice you rarely build this by hand. Ready services like Supabase, Clerk, or Auth0 issue and verify JWTs for you — often paired with OAuth "sign in with Google" login. But now, when something breaks, you understand exactly what's happening under the hood.
FAQ
Is a JWT the same as a cookie?
Not quite. A cookie is a storage location in the browser; a JWT is the format of the token itself. JWTs are often placed inside a cookie (convenient and safe), but can be stored other ways too. So it's not either/or: a JWT-format token lives perfectly well inside a cookie.
Where should I store a JWT on the client?
The safest option is in a cookie with the httpOnly flag: then page JavaScript can't reach the token. Storing it in localStorage is simpler but riskier — an injected-script attack could steal it. To start, trust how your auth service does it by default.
Why have a refresh token if I already have a JWT?
To combine safety and convenience. The main token is made short-lived — if stolen, it expires fast. And so you aren't kicked out every 15 minutes, a long-lived refresh token sits alongside it: it silently issues a new main token while you're active.
Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.





