Security · applied
Login, Sessions & Auth
HTTP forgets you after every request, so login has to manufacture memory — safely, without ever touching a plaintext password.
Stateless HTTP + plaintext passwords = disaster
Every request arrives with no memory of the last one — so how does the server know request #2 is still "alice"? And if the password table is stored as-is, one breach hands over every account.
// ✗ never do this
const users = {
alice: { password: "hunter2" } // plaintext!
};
// DB leak → every password exposed, instantly,
// including any site where a user reused it.
Verify a salted hash, then hand back a credential
const ok = await bcrypt.compare(pw, user.hash);
if (!ok) throw Error("401");
// stateful: server stores the session
session.id = randomId();
store.save(session.id, user.id);
// or stateless: self-contained token
const token = jwt.sign(
{ sub: user.id }, secret, { expiresIn: "15m" }
);
Session cookie: server keeps the state — trivial to revoke, needs a lookup per request. JWT: stateless and self-contained — scales without a store, but revoking one token before it expires is hard. Either way: short expiries, refresh tokens to renew silently, and a real logout path that deletes the session or blacklists the token.
Log in, call the API, watch the session expire
Fixed user alice / secret123. Time is a logical clock (ticks), not the wall clock —
so the demo is deterministic every run.
Try the wrong password first, then the correct one.
— log empty —
Hash it, expire it, and be ready to revoke it
- Never store plaintext. Salt + hash with bcrypt or argon2 — compare with a constant-time check.
- Sessions vs JWT is a tradeoff: easy revocation + server state, vs. statelessness + harder revocation.
- Short expiries + refresh tokens limit the damage window of a stolen credential.
- HttpOnly + Secure cookies keep tokens out of reach of JavaScript and off plain HTTP.
- Add MFA for a second factor, and rate-limit the login endpoint against credential stuffing.