Cookies are small pieces of data stored in the browser, typically set by the server using the Set-Cookie header.
They can include attributes such as:
Max-Age / Expires β defines how long the cookie is valid
HttpOnly β prevents access from JavaScript (improves security - it cannot be accessed by JS using document.cookie XSS attacks)
Secure β ensures the cookie is only sent over HTTPS
SameSite β controls cross-site request behavior
π Authentication flow using cookies (server-side sessions)
- User logs in with credentials
- Server: Creates a session (stored in DB/memory) Generates a session ID Sends it to the browser via:
Set-Cookie: session_id=abc123
**Browser:
**Stores the cookieAutomatically includes it in future requests:
Cookie: session_id=abc123
Because they are sent with every request (including images/scripts), large cookies can impact performance
π Cookie behavior in requests
For same-origin requests β cookies are sent automatically
For cross-origin requests β must explicitly enable:
Frontend: credentials: "include" or withCredentials: true
Backend: Access-Control-Allow-Credentials: true
β³ Expiry behavior
Session cookies (no expiry):
Deleted when browser closes
Persistent cookies (with Max-Age / Expires):
Remain after browser restart
β οΈ** Important distinction**
Cookie expiry and session expiry are separate:
Cookie expiry β controlled by browser
Session expiry β controlled by server
Even if a cookie is still valid, the user is logged out if the server session has expired.
Key takeaway
Cookie = identifier stored in browser
Session = actual user data stored on server
Cookie is automatically sent with requests (with some cross-origin rules
Challenges
In a distributed system with multiple backend servers behind a load balancer, session-based authentication can be harder to scale because sessions are stored on the server side and creates challenges like session sharing, synchronization, and additional database or cache lookups on every request
If a session is stored on one server and a subsequent request is routed to a different server, that server wonβt recognize the session, making the user appear logged out.
To solve this, systems typically use a shared session store like Redis or a database that all servers can access. However, this introduces additional overhead because every request requires a lookup to fetch session data, which adds latency and increases infrastructure complexity.
This is why session-based systems are considered stateful and harder to scale compared to stateless approaches like JWT.
CSRF = Cross-Site Request Forgery
π Itβs an attack where:
A malicious website tricks your browser into making a request to another site where you are already logged in.
CSRF is an attack where a malicious site tricks a userβs browser into making unintended requests to another site where the user is authenticated. It happens because cookies are automatically sent with requests. CSRF tokens prevent this by adding a secret value that must be validated by the server.
Browsers automatically send cookies with requests
Thatβs the root cause.
JWT
JWT (JSON Web Token) is a self-contained token that carries user information and proves authentication.
it is compact URL-safe means of representing claims to be transferred between two partiesβ. A JWT leverages Javascript Object Notation (JSON) to represent these claims, resulting in a small and simple token that is used by protocols such as OpenID Connect 1.0 to represent identity to the application and OAuth 2.0 to represent an access token for API authorization.
Structure:
header.payload.signature
Header β algorithm (e.g., HS256)
Payload β user data (userId, role, exp)
Signature β ensures integrity (not tampered)
π Signing (Data Integrity)
Server signs the token using a secret key
Signature ensures
- Token is issued by server
- Data is not modified
π If payload changes β signature becomes invalid
β οΈ JWT is NOT encrypted by default
Payload is base64 encoded (readable)
Anyone can decode it
But cannot modify it (signature protects it)
π Do NOT store sensitive data in JWT
π JWT Authentication Flow
- User logs in
- Server generates JWT
- Client stores token
- Client sends token in requests:
Authorization: Bearer <token>
Server verifies signature β authenticates user
π¦ Where to store JWT
- localStorage β Pros:
- Easy to use
- Full control in frontend β Cons:
- Vulnerable to XSS attacks (JS can read token)
- Cookies (HttpOnly) β Pros:
- Protected from XSS (HttpOnly)
- Automatically sent with requests β Cons:
- Vulnerable to CSRF attacks
Storage Risk
localStorage XSS
Cookies CSRF
β
Best practice
Store JWT in HttpOnly cookies
Use:
Secure
SameSite
π¨ CSRF (Cross-Site Request Forgery)
π§Ύ Example
You are logged into bank.com
Attacker site triggers:
<img src="https://bank.com/transfer?amount=1000">
Browser sends:
Cookie: session_id=abc123
π Server thinks request is valid
π‘οΈ** CSRF Protection**
- CSRF Token (core idea)
π Add a secret token that attacker cannot access
π Synchronizer Token Pattern
- Server stores
- session β csrf_token
- Sends token to client
- Client sends it back
- Server validates
π Double Submit Cookie Patter
Step 1: Server sends cookies
session_id=abc123 (HttpOnly)
csrf_token=xyz789 (readable by JS)
Step 2: Client sends request
Cookie: session_id=abc123; csrf_token=xyz789
Header: X-CSRF-Token: xyz789
Step 3: Server validates
cookie csrf_token === header csrf_token
β
Why it works
Attacker cannot:
Read cookie
Set custom headers
π Request is rejected
- SameSite Cookies Set-Cookie: session_id=abc123; SameSite=Strict
π Prevents cookies in cross-site requests
π Access Token vs Refresh Token
π§Ύ Access Token
Short-lived (e.g., 15 min)
Used for API requests
Authorization: Bearer
π Refresh Token
Long-lived (e.g., 7 days)
Used to get new access tokens
β οΈ Important Concepts Summary
Integrity vs Confidentiality
Integrity β data not modified (JWT provides this)
Confidentiality β data hidden (JWT does NOT provide by default)
Sessions vs JWT
Session β server stores data (stateful)
JWT β client carries data (stateless)
CSRF vs XSS
Attack Target
CSRF Cookies (auto-sent)
XSS localStorage / JS-accessible data
Top comments (0)