What is the difference between cookies, sessions and tokens like JWT?
A cookie is just a small piece of data the browser stores and sends back automatically. A session keeps login state on the server and puts only a random session ID in a cookie. A JWT is a signed token that carries the user's data itself, so the server can verify it without a lookup, but it is harder to revoke before it expires.
Explain it simply
HTTP has no memory. Every request arrives as a stranger, so after you log in, the server needs a way to recognise you on the next request.
- A session is like a cloakroom at a wedding hall. You hand over your bag and get a numbered token. The token itself means nothing; the hall keeps the real record of what token 57 owns. If the hall cancels token 57, it is useless at once.
- A JWT is like a signed gate pass from the college office: "Ravi, CSE, allowed in the lab until 6 pm", with the principal's signature. The guard does not need to call the office; checking the signature is enough. But if the pass is stolen, it works until 6 pm unless the guard has a list of cancelled passes.
- A cookie is the pocket you carry either of them in. It is a storage and delivery mechanism, not a login method by itself.
Example
Session-based login:
POST /login (username, password)
<- 200 OK
Set-Cookie: sid=4f9c2e...; HttpOnly; Secure; SameSite=Lax; Path=/
GET /profile
Cookie: sid=4f9c2e...
Server looks up sid in Redis -> user 42 -> respondsToken-based login with a JWT:
POST /login
<- 200 OK { "access_token": "eyJhbGciOiJIUzI1NiIs...", "expires_in": 900 }
GET /api/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Server checks the signature and expiry -> reads "sub": "42" -> respondsA JWT has three base64url parts separated by dots: header.payload.signature. A decoded payload might be:
{ "sub": "42", "role": "student", "iat": 1790900000, "exp": 1790900900 }How it works
Cookies. The server sends Set-Cookie, and the browser stores it and attaches it to later requests to that site. Important attributes:
HttpOnly: JavaScript cannot read it, which protects it from being stolen through XSS.Secure: sent only over HTTPS.SameSite:Strict,LaxorNone, controls whether it is sent on cross-site requests, which is the main defence against CSRF. Modern browsers treat cookies without this attribute asLax.Max-AgeorExpires: without them, it is a session cookie that disappears when the browser closes.
Sessions. The server stores state (user ID, cart, roles) in memory, a database or Redis, keyed by a long random ID. The client only holds the ID. Logout or "log out of all devices" is easy: delete the server record. The cost is a lookup on every request, and with many servers, a shared store.
JWTs. The server signs the header and payload with a secret (HS256) or a private key (RS256, ES256). Any service with the secret or public key can verify it without a database call, which suits microservices and mobile apps. But the payload is only encoded, not encrypted; anyone can decode and read it. And since the server keeps no record, revoking one token early needs extra work, such as a deny list or short expiry.
Real-world use
A typical server-rendered web app uses sessions in HttpOnly cookies. Many mobile and single-page apps use a short-lived JWT access token (5 to 15 minutes) plus a long-lived refresh token, so a stolen access token expires quickly and the refresh token, which is stored securely and can be revoked on the server, gets new ones. "Login with Google" uses OAuth 2.0 and OpenID Connect, where the ID token is a JWT.
Common mistakes
- Saying "cookies vs JWT" as if they are alternatives. A JWT can be stored in a cookie; the real choice is server-side state vs self-contained tokens.
- Putting passwords, Aadhaar numbers or other secrets in a JWT payload. Anyone holding the token can read it.
- Storing tokens in
localStorage, where any XSS script can read them. - Issuing JWTs that last for days with no way to revoke them.
- Not checking the algorithm on the server, which allowed old attacks like accepting
alg: noneor confusing HS256 with RS256. Always pin the expected algorithm. - Forgetting CSRF protection when auth is in cookies.
What to say in the interview
"A cookie is a browser storage mechanism that is sent automatically with requests; it carries auth but is not auth itself. With sessions, the server stores the user's state and gives the browser a random session ID in an HttpOnly, Secure, SameSite cookie, so revocation is easy but every request needs a lookup in a shared store. A JWT is a signed, self-contained token with claims like user ID and expiry. Servers verify the signature without a database, which scales well across services, but the payload is readable and revocation is hard, so I keep access tokens short-lived and pair them with revocable refresh tokens. For a typical web app I prefer sessions in HttpOnly cookies; for APIs used by mobile apps or many services, JWTs fit better."
Follow-up questions
- How do you log a user out everywhere if you use JWTs?
- What are XSS and CSRF, and how do cookie attributes help against each?
- Where should a single-page app store its tokens?
- What is the difference between HS256 and RS256?
Go deeper
Read these once the basics above feel easy.
With RS256 or ES256, only the auth server holds the private key, and every other service verifies tokens with the public key, often fetched from a JWKS endpoint. This means a compromised API service cannot mint new tokens. Always validate exp, iss (issuer) and aud (audience), not just the signature, or a token issued for one app may be accepted by another.
Refresh token rotation issues a new refresh token on every use and invalidates the old one. If an old refresh token is ever presented again, the server treats it as theft and revokes the whole token family. For browser apps, a common hardened design is the backend-for-frontend pattern: the browser holds only an HttpOnly session cookie to its own backend, and that backend keeps the OAuth tokens server-side, so no token is ever exposed to JavaScript.