
Session Hijacking Starts With Your Cookies — Here's What You Missed
Most developers think session hijacking is an advanced attack. It's not. It usually starts with something very basic: your cookies. Learn the 3 flags and token refresh pattern that actually works.
TL;DR
Most developers think session hijacking is an advanced attack. It's not. It usually starts with something very basic: your cookies. Learn the 3 flags and token refresh pattern that actually works.
Most developers think session hijacking is some "advanced hacker attack".
It's not.
It usually starts with something very basic: your cookiesyour cookies
A Small Mistake That Becomes a Big Problem
A real situation I've seen:
- App was using JWT stored in cookies
- Everything worked fine in dev and staging
- Deployed to production
- But:
👉 Cookies were not marked Secure
👉 Someone on the same network intercepted traffic
👉 Session got reused
No password needed. No brute force. Just cookie reuse.
🤔 Why Cookies Matter More Than You Think
When you log in:
- Server gives you a session or token
- Browser stores it (usually in cookies)
- Every request automatically includes it
👉 That cookie is your identityThat cookie is your identity
If someone gets it → they are you.
How Session Hijacking Actually Happens
Common real-world paths:
1. Network Interception (HTTP / insecure setups)
- Using public WiFi
- Traffic not encrypted properly
- Cookies sent in plain text
2. XSS (Cross-Site Scripting)
document.cookieIf your cookie is readable → attacker can steal it.
3. CSRF (Cross-Site Request Forgery)
Browser automatically sends cookies:
👉 Even when request is triggered from another site
4. Token Leakage (logs / frontend)
- Logging tokens accidentally
- Exposing via frontend (localStorage, window)
The Problem Most JWT Articles Don't Explain
Everyone talks about:
- "Use JWT"
- "Store token"
- "Use refresh token"
But they don't tell you:
👉 Where you store the token matters more than the token itselfWhere you store the token matters more than the token itself
🔐 The 3 Cookie Flags You Should NEVER Ignore
1. HttpOnly — Protect Against XSS
What it does:
👉 Prevents JavaScript from accessing cookies
Set-Cookie: token=abc123; HttpOnlyWhy it matters:
Even if XSS exists:
document.cookie // ❌ cannot access HttpOnly cookies2. Secure — Only Over HTTPS
What it does:
👉 Cookie is sent ONLY over HTTPS
Set-Cookie: token=abc123; SecureWhy it matters:
- Prevents MITM attacks
- Protects on public networks
3. SameSite — Protection Against CSRF
Options:
SameSite=Strict // safest
SameSite=Lax // balanced
SameSite=None // required for cross-domain (must use Secure)Why it matters:
👉 Prevents browser from sending cookies in cross-site requests
What a Secure Cookie Setup Actually Looks Like
Set-Cookie: accessToken=xyz;
HttpOnly;
Secure;
SameSite=Strict;
Path=/;👉 This should be your default baseline
🔄 Token Refresh Pattern (Where Most Apps Fail)
Many apps do this wrong:
❌ Store long-lived JWT in browser
❌ No refresh logic
❌ Token valid for days✅ Correct Pattern
Access Token
- Short-lived (5–15 min)
- Stored in HttpOnly cookie
Refresh Token
- Longer-lived
- Stored securely (also HttpOnly cookie)
Flow:
- User logs in
- Server sends:
- accessToken (short life)
- refreshToken (long life)
- Server sends:
- When access token expires:
- frontend calls /refresh
- server verifies refresh token
- issues new access token
👉 Even if access token leaks → damage is limited
Common Mistakes (I See This A LOT)
❌ Storing JWT in localStorage
localStorage.setItem("token", token);👉 Easily accessible via XSS
❌ Missing Secure flag in production
👉 Works in dev → breaks security in prod
❌ Using SameSite=None without Secure
👉 Browser may reject or expose cookie
❌ Logging tokens
console.log(req.headers.authorization);👉 Logs = permanent leak
❌ Sharing tokens across subdomains without isolation
👉 One compromised app = all sessions compromised
How This Connects To Your Previous JWT Article
Your JWT article likely covered:
- Token generation
- Signing
- Validation
This article completes it:
👉 Storage + transport securityStorage + transport security
Because:
A perfectly signed JWT is useless if it's stolen.
Practical Setup (Based on Your Stack)
You are using:
- Next.js
- Node.js
- Backend (Node.js / Express)
Express setup:
res.cookie("accessToken", token, {
httpOnly: true,
secure: true,
sameSite: "strict",
});Next.js (API routes)
Use cookies, NOT localStorage.
Docker / NGINX
👉 Ensure HTTPS termination is correct
👉 Otherwise Secure flag won't work properly
Final Thought
Most developers secure:
- Passwords
- APIs
- Database
But forget:
👉 the thing that represents the user session
And that's the easiest entry point.
🚀 What You Should Do Today
- Check your cookies in DevTools
- Verify flags:
- HttpOnly ✅
- Secure ✅
- SameSite ✅
- Remove tokens from localStorage
- Implement refresh token flow
Enjoying this article?
Get new articles, tips, and fixes delivered straight to your inbox — free, no spam.
Was this article helpful?
Let me know if this was useful — it helps me write more content like this.
What's next?
Daily Challenge
Put it into practice
Try today's hands-on dev challenge — takes under 5 minutes.
Open challengeRelated Tool
JWT Decoder
Free browser-based dev tool — no sign-up needed.
Open toolQuick Tip
30-second dev lessons
Browse tips, fixes, and bugs — bite-sized and practical.
Browse tipsNew challenge and tips drop daily. Come back tomorrow to keep your streak going.
Related Articles
You might also enjoy these
Your Node.js API Is Doing the Same Work Over and Over — Redis Fixes That
Your API is running the same database query hundreds of times a minute. Redis caching fixes that — response times drop from 400ms to under 10ms. Here's the complete setup: client config, cache-aside pattern, per-user keys, cache invalidation, and a reusable Express middleware.
Rate Limiting Isn't Optional - Here How to Actually Implement It in Node.js
No rate limiting means any client can hit your API as many times as it wants. This guide walks through the right way to implement it in Node.js - from express-rate-limit basics to Redis-backed sliding windows and layered per-route limits that work in production.
CORS Isn't a Bug - It's Your API Trying to Warn You (And You Ignored It)
Stop fighting CORS. Understand preflight requests, credentials, wildcard mistakes. CORS isn't a bug—it's your API warning you about real security issues.



Comments
Leave a Comment
All comments are reviewed before publishing