How I Finally Understood Sessions, Cookies, and JWT
When I first started building auth systems, everything felt mixed up.
People were throwing terms like:
sessions
cookies
JWT
And I was like…
“Aren’t they all just login things?”
Turns out… not really.
It started with a simple question
I had this basic doubt:
“After login… how does the server remember the user?”
Because HTTP is stateless.
Meaning:
every request is independent
server forgets everything after response
So how does it know:
“this request is from the same user”?
That’s where all of this comes in.
First thing I learned: Cookies
Cookies are the simplest piece.
A cookie is just:
small data stored in the browser
Example:
Set-Cookie: userId=123
Now every request automatically sends:
Cookie: userId=123
So the server can recognize the user.
That’s it.
Nothing magical.
Then I learned: Sessions
Sessions build on top of cookies.
Here’s how I think about it:
Server creates a session object
Stores it (DB / memory)
Sends a session ID in cookie
Flow in my head:
User logs in
Server creates session →
{ userId: 123 }Server sends cookie →
sessionId=abc123Browser stores it
Every request sends that cookie
Server looks up session using that ID
User → Login
Server → Create session (store in DB)
Server → Send sessionId in cookie
Next request:
User → sends cookie
Server → finds session → knows user
Then came JWT
At first I thought JWT is just another session.
But it’s different.
JWT is:
a token that contains the data itself
Example (simplified):
{ userId: 123 }
Encoded and signed.
JWT flow
User logs in
Server creates token (JWT)
Sends it to client
Client stores it (localStorage / cookie)
Every request sends token
Server verifies token → gets user info
No DB lookup needed.
User → Login
Server → Generate token
Server → Send token
Next request:
User → sends token
Server → verifies → knows user
The real difference (stateful vs stateless)
This part took me time.
Sessions = Stateful
Server stores data
JWT = Stateless
Server stores nothing
Session vs JWT
| Feature | Session Auth | JWT Auth |
|---|---|---|
| Storage | Server (DB / memory) | Client (token) |
| Server load | More (needs lookup) | Less (no lookup) |
| Scalability | Harder | Easier |
| Control | Easy to invalidate | Hard to invalidate |
| Size of request | Small (just session ID) | Larger (token sent every time) |
| Setup | Simple | Slightly complex |
What I personally use
When I started building projects, I noticed:
Use Sessions when:
simple apps
server-rendered apps
admin panels
you want easy logout / control
Use JWT when:
APIs
mobile apps
frontend + backend separate
scaling matters
One mistake I made early
I tried using JWT everywhere.
Bad idea.
Because:
logout is tricky
token invalidation is messy
That’s when I realized:
JWT is not “better” — it’s just different
How I think about it now
I don’t overcomplicate it anymore.
I just ask:
“Where should the user state live?”
If server → use session
If client → use JWT
That’s it.
Final thought
This whole topic confused me for a long time because I tried to memorize it.
But once I saw it in flow:
cookie → just storage
session → server remembers
JWT → client carries identity
Everything became simple.
