Authentication on the Web: Sessions vs JWTs
Understand how users stay logged in — and how we as pentesters can take advantage of it.
Authentication is the process of proving who you are. Every time you log in to a website — with a username and password — you’re authenticating.
But logging in is just step one.
What really matters is what happens after you log in:
How does the site remember you for the next request, the next page, or the next day?
That’s where sessions and tokens come in.
Analogy: Session vs Token
Imagine walking into a nightclub.
- With Sessions, the bouncer gives you a wristband. He knows you’re on the guest list and checks that wristband every time you move.
- With Tokens, you get a digital badge that proves you’re VIP. You show it to every staff member, and they verify it — the bouncer doesn’t have to remember anything about you.
Method 1: Session-Based Authentication (Traditional)
How It Works:
- You
POSTyour username and password. - If correct, the server creates a session — like a file or object stored in memory.
- The server sends a session ID to your browser as a cookie:
Set-Cookie: sessionid=abc123; - Your browser includes that cookie in every future request:
Cookie: sessionid=abc123
The server uses that session ID to check if you’re logged in.
Key Concepts:
| Term | Meaning |
|---|---|
| Session ID | Random ID pointing to your session data on the server |
| Session Store | Where user data lives (in memory, on disk, in a DB) |
| Cookie | How the session ID is sent back to the server |
Example:
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin&password=letmein
Server response:
HTTP/1.1 200 OK
Set-Cookie: sessionid=abc123;
Every future request will include:
GET /profile HTTP/1.1
Cookie: sessionid=abc123
Common Pentest Issues with Sessions:
- Session Fixation (reuse a known session ID)
- Session Hijacking (steal session ID via XSS)
- No session timeout
- No Secure or HttpOnly flags on cookies
Method 2: Token-Based Authentication (Modern / API-Friendly)
How It Works:
- You
POSTyour login info to/login - Server returns a token (usually a JWT)
- You store the token (in browser storage or memory)
- For every request, you include:
Authorization: Bearer <your_token_here>
No session data is stored on the server. Everything the server needs is inside the token itself.
What Is a JWT?
A JSON Web Token (JWT) is a compact, base64-encoded string with 3 parts:
<header>.<payload>.<signature>
Example payload:
{
"username": "admin",
"admin": true,
"exp": 1730000000
}
The signature is used to ensure the token wasn’t tampered with.
JWT Login Example:
curl -X POST https://site.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin", "password":"letmein"}'
Response:
{
"status": "success",
"auth_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6..."
}
You now include this token on every request:
GET /api/users
Authorization: Bearer eyJhbGciOi...
JWT Pros:
- Stateless (server doesn’t need to store sessions)
- Ideal for mobile apps and APIs
- Can include custom claims (e.g.,
"admin": true) - Scalable across microservices
JWT Cons:
- Token can’t be revoked easily (unlike sessions)
- Stored in browser = risk of XSS theft
- If signed with a weak secret or misconfigured (
alg: none) → easy to forge - Bigger payloads = more exposure if intercepted
Summary: Session vs JWT
| Feature | Sessions | JWTs |
|---|---|---|
| Stored where? | On the server | On the client |
| Stateless? | ❌ No | ✅ Yes |
| Sent via | Cookies | Authorization header |
| Revocable? | ✅ Yes | ❌ Not easily |
| Best for | Websites | APIs, mobile, SPA apps |
| Security risks | Cookie hijacking | Token forgery, XSS theft |
Why This Matters in Pentesting
As a pentester, knowing how the app handles authentication lets you plan your attacks:
If it’s session-based:
- Look at the cookie: can it be stolen, reused, manipulated?
- Is it missing flags like
Secure,HttpOnly,SameSite? - Can you force a session ID via Fixation?
If it’s token-based:
- Decode the JWT: what’s in the payload?
- Is it signed with a weak secret? Can you crack it?
- Does the app blindly trust the token without rechecking backend permissions?
Quick Tricks to Tell Which One You’re Dealing With
| Sign | What It Means |
|---|---|
Set-Cookie: in response | Likely session-based |
Authorization: Bearer in requests | Likely JWT/token-based |
| Long base64-looking string in localStorage | Probably a JWT |
| Burp proxy shows consistent cookie values | Sessions |
| Reuse of static tokens across requests | JWTs or API keys |
Tools to Play With
| Tool | Use |
|---|---|
Burp Suite | See headers, cookies, tokens |
jwt_tool.py | Decode, fuzz, and attack JWTs |
Postman | Test with headers, cookies, tokens |
curl | Send raw requests manually |
httpie | Easier-to-read version of curl |
Next Steps for You
✅ Watch what headers go in and out of login requests
✅ Practice stealing/modifying cookies vs tokens
✅ Decode JWTs and inspect their claims
✅ Test endpoints both with and without tokens
✅ Try using expired or modified tokens — how does the app react?
Authentication is one of the most important aspects of modern web apps — and one of the most abused.
Once you know the difference between Sessions and JWTs, you know where to look, what to manipulate, and how to go from login to full compromise.
