Sharing notes from my ongoing learning journey — what I build, break and understand along the way.
Cookies & Sessions: How Remember Me Works — Safely
Cookies & Sessions: The Beginner-Friendly Security Guide
Cookies & Sessions on the Web: The Story Behind “Remember Me”
Quick summary: A cookie in your browser is a tiny note; a session on the server is the actual file that remembers you. The safe setup is simple: HTTPS, HttpOnly, Secure, SameSite. Keep only a meaningless session ID in the browser; store real data on the server.
Why do we need this?
I log in to a site and it doesn’t ask for my password again after a refresh. I add an item to my cart and it’s still there on the next page. I tick “remember me” and the site knows me a week later.
What makes that comfort possible? Two small helpers: cookies and sessions.
- Cookie: A small card in my browser’s wallet. The site writes a number on it, and every time I visit, the browser shows that card to the site.
- Session: A file in the site’s vault. The site looks up the number on the card and recognizes me—cart, roles, preferences—all live there.
In short: The cookie is the carrier; the session is what’s actually remembered.
What exactly does a cookie do?
The site gives my browser a tiny note. That note is usually a random, hard-to-guess session number. On its own it means nothing; the server uses it to find “the file.”
My ground rules:
- Only through the locked door: Send the cookie only over HTTPS (Secure).
- Keep it out of page scripts: The easiest place for thieves to peek is page JavaScript; make the cookie HttpOnly.
- Don’t tag along on cross-site tricks: SameSite keeps the cookie from being sent with sneaky, cross-site requests (for most apps, Lax is ideal).
So what’s a session?
A session is a small file on the server: who I am, what’s in my cart, what I’m allowed to do. The browser only carries the file number. Even if the note is stolen, the real data isn’t in the browser—it’s on the server.
Some systems use signed tokens (e.g., JWT). That can be handy in distributed setups, but then you must enforce short lifetimes, solid refresh/revocation strategy, and secure storage.
Step by step: How does login work?
- I submit my credentials.
- The server verifies them.
- The server creates a random session ID and hands it to my browser as a cookie.
- As I browse, my browser quietly sends that number back; the server recognizes me.
Two small boosts for safety:
- Rotate the session right after login (defuses session-fixation tricks).
- Keep sessions short-lived: auto-expire on inactivity (say 20–30 min) and set a daytime cap (e.g., 12 hours).
Security Essentials in Plain Language
- No HTTPS, no party. Without encryption, someone on the wire can read your note.
- HttpOnly keeps the cookie out of JavaScript; even with an XSS hole, the script can’t read it.
- SameSite cuts down “do stuff without my knowledge” attacks (CSRF).
- Short durations. Don’t leave sessions open forever; “remember me” can live longer, but keep it reasonable.
- Mind your subdomains. Don’t spray cookies across every subdomain—narrow scope is safer.
Quick Q&A
Can I just put my username or role in the cookie?
Don’t. Anything in the browser can be seen or tweaked. Carry only a meaningless ID.
What if I switch devices?
You’ll get a new session on the new device. If you want, a “log out from all devices” action can kill every server-side session.
I have subdomains (app., admin., …). Should they all see the same cookie?
Keep scope as tight as possible. Isolating critical areas is safer.
My quick checklist
- HTTPS required
- Session cookie: HttpOnly + Secure + SameSite (usually Lax)
- Rotate after login
- Short idle timeout and a hard daily cap
- Extra confirmation for high-risk actions (CSRF protection, re-auth, etc.)
- Minimal cookie scope (avoid broad
Domain
/wide exposure)
Mini technical corner
For when you want to peek under the hood.
Example of a server-set cookie
Set-Cookie: __Host_session=R0xw1u...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=1800
__Host_
prefix: Stricter rules (HTTPS, noDomain
,Path=/
).Secure
: Sent only over HTTPS.HttpOnly
: Not readable by JavaScript.SameSite=Lax
: Not sent on most cross-site requests, except top-level navigations.Max-Age=1800
: 30-minute lifetime.
Authenticated request
GET /api/me
Cookie: __Host_session=R0xw1u...
Logout
# Server: invalidate the session (e.g., delete DB/Redis record)
# Client: expire the cookie in the past
Set-Cookie: __Host_session=; Path=/; Secure; HttpOnly; SameSite=Lax; Expires=Thu, 01 Jan 1970 00:00:00 GMT
Optional note (for JWT users)
- Access token should be very short-lived (5–15 min).
- Refresh token in a separate cookie (HttpOnly+Secure) with rotation.
- Use a revocation list/session table to handle edge cases.
In Short
The core is simple: the browser carries a tiny number, the server uses it to recognize you.
What keeps the magic safe are short lifetimes, the right flags (HTTPS, HttpOnly, Secure, SameSite), and the habit of never leaving real secrets in the browser. With that foundation set, I can build on top with confidence.