From Cookies to JWT: How Authentication Actually Makes Sense
Most tutorials start with JWT.
I had to start with confusion.
When I first learned authentication, everything felt magical in the worst way.
- Cookies appeared from nowhere
- Sessions lived “on the server” (somewhere?)
- JWTs were called stateless — yet they somehow knew who I was
I could implement authentication, but I didn’t understand it.
So I decided to rewind — not to frameworks, but to the problem authentication was trying to solve.
Step 1: “I just want the user to stay logged in”
You build your first website.
There’s a login form:
- username
- password
The user logs in successfully.
Then they click another page.
-> New HTTP request.
HTTP doesn’t remember anything.
So the real question becomes:
How do I know this is the same user?
Step 2: Sessions — the first solution that makes sense
The simplest workable idea is this:
- User logs in
- Server creates a session
- Server sends a session ID back to the browser (via a cookie)
- Browser sends that cookie on every request
- Server looks up the session → user found → authenticated
The browser stores something like:
session_id=abc123The server stores everything else:
- who the user is
- their roles
- expiry time
This is called stateful authentication.
The server remembers you.
The browser just carries an ID card.
And honestly — this model is brilliantly simple.
Step 3: “Wait… wasn’t there something even simpler?”
Yes. Basic Authentication.
Every request looks like this:
Authorization: Basic base64(username:password)No cookies.
No sessions.
No memory.
Just credentials. Every time.
At first, you might think:
“Do users really type their password on every request?”
- No.
The hidden twist…
Browsers cache the credentials internally and automatically attach them to every request.
So the next time you:
CTRL + Clickan internal link- Open a link in a new tab
- Refresh the page
…and you’re still authenticated — it starts feeling like a session.
But it isn’t.
There’s no session ID.
No server-side memory.
Your username and password are still being sent on every request.
⚠️ That’s the dangerous part.
This is where an important lesson appears:
Convenience is not the same as security.
Step 3.5: Why everything still feels the same (and why that’s misleading)
At this point, everything still feels like magic.
Whether it’s Basic Auth, sessions, or JWT —
opening a new tab and staying logged in looks exactly the same.
That’s because the browser doesn’t understand authentication.
It only knows how to automatically resend headers.
The difference isn’t visible in behavior.
It lives in what travels with every request, and who controls it.
Same UX.
Completely different security model.
Step 4: Why sessions felt like a huge upgrade
Sessions fixed almost everything Basic Auth got wrong.
If someone steals your session cookie, they can impersonate you —
but they don’t learn your password.
That’s a massive improvement.
For a long time, sessions were the answer.
Step 5: The problem wasn’t sessions — it was scale
Sessions work perfectly…
until your application grows.
Get Keshav Patel’s stories in your inbox
Join Medium for free to get updates from this writer.
Imagine this:
- User logs in → Server A creates session
- Next request goes to Server B
- Server B has no idea who this user is
Now you need:
- sticky sessions, or
- shared session storage (Redis, DB)
More infrastructure.
More complexity.
And eventually, someone asks:
“What if the server didn’t remember users at all?”
That’s the birth of stateless authentication.
Step 6: Stateless auth (the mental shift)
Stateless authentication means:
Every request must prove who you are — by itself.
We already tried this once (Basic Auth), and it failed.
So the new rules became:
- Don’t resend the password
- Don’t store user state on the server
- Still be able to trust the client
This is the exact problem JWT was designed to solve.
Step 7: JWT — not magic, just signed facts
A JWT is not encryption.
It’s tamper-proof data.
Inside a JWT is a JSON payload like:
{
"user": "alpha",
"roles": ["ADMIN"],
"exp": 1700000000
}The server:
- Signs it with a secret key
- Sends it to the client
The client:
- Sends it back on every request
The server:
- Verifies the signature
- Checks expiry
- Trusts the data
No session lookup.
No shared store.
No memory.
The server doesn’t remember you.
It trusts what it signed.
Step 8: Is JWT “better” than sessions?
No.
JWT is different, not superior.
Sessions
- Easy logout
- Easy revocation
- Server-controlled
- Stateful
JWT
- Scales effortlessly
- Ideal for APIs & mobile
- Harder to revoke
- Stateless
JWT wasn’t created because sessions were bad.
JWT exists because systems stopped living on one machine.
Step 9: The real security truth people skip
A common fear:
“If someone steals my JWT, can they use it?”
Yes — if the client is already compromised.
And that leads to the most important security mindset:
Security is about damage control, not perfection.
That’s why real systems use:
- short-lived tokens
- refresh tokens
- HTTPS
- revocation strategies
JWT doesn’t remove risk.
It limits the blast radius.
Final takeaway
Authentication didn’t evolve randomly, It evolved because constraints changed:
- Basic Auth → too naive
- Sessions → great UX, stateful
- Scaling → sessions hurt
- JWT → stateless trust
Once you see the journey, authentication stops feeling magical.
It becomes… logical.








