Stop 08 · Authentication Across the StackTopics · 1/8

Sessions vs Tokens

Part of the Full Stack Developer Roadmap

In short

HTTP forgets you after every request. After login, your app must recognise the same person on the next click. Sessions and tokens are the two main ways, and each changes how your backend is built.

The two dominant approaches to remembering a logged-in user — server-side sessions (stateful, stored in a DB/Redis) vs tokens like JWT (stateless, verified without a lookup) — each with different trade-offs for a full-stack app.

The mascot holds up a stamped pass while a guard flips through a thick register.

Think of it like this

Gate register vs signed gate pass

At one library, the guard writes your name in a register and checks it each time you return. At another, the principal gives you a signed, dated gate pass, and any guard can trust the signature without a register. Register is a session. Signed pass is a token.

Watch it happen

Remembering a logged-in user

Session

  • Server stores session in DB or Redis
  • Browser keeps only a random ID cookie
  • Logout deletes the row, instantly

Token (JWT)

  • Signed token carries user id and expiry
  • Server checks signature, no lookup needed
  • Hard to cancel before it expires

For one web app with its own backend, sessions in httpOnly cookies are simpler and easier to revoke. JWTs help when many services or mobile apps must verify users.

The big ideas

What you need to know

Cookies are the transport

Both can travel in a cookie. httpOnly stops JavaScript reading it, which protects you if an XSS bug sneaks in.

Short-lived tokens

Keep JWTs short, around 15 minutes, and use a refresh token stored server-side to get new ones.

Avoid localStorage for auth

Any script on the page can read localStorage. A single XSS bug would leak every user's token.

JWTs aren't secret

The payload is only base64 encoded. Anyone can decode it, so never put passwords or private data in it.

See it in code

Walk through the code

ts
1// Option A: session (express-session + a store like Redis)2app.use(session({3  secret: process.env.SESSION_SECRET!, resave: false, saveUninitialized: false,4  cookie: { httpOnly: true, secure: true, sameSite: "lax", maxAge: 7 * 24 * 3600 * 1000 },5}));6app.post("/login", async (req, res) => {7  const user = await checkPassword(req.body.email, req.body.password);8  req.session.userId = user.id; // stored on the server, browser gets a session ID cookie9  res.sendStatus(204);10});11 12// Option B: JWT (jsonwebtoken)13const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET!, { expiresIn: "15m" });14res.cookie("token", token, { httpOnly: true, secure: true, sameSite: "lax" });15// later, on each request:16const payload = jwt.verify(req.cookies.token, process.env.JWT_SECRET!);

1/4Session middleware with a secure, httpOnly cookie that JavaScript can't read.

Both send a cookie. The difference is where the truth lives: in your session store, or inside the signed token.

Save yourself the pain

Common mistakes

Oops

Storing the JWT in localStorage because a tutorial did it.

Do this instead

Prefer an httpOnly, Secure, SameSite cookie, so page scripts can't read it.

Oops

Issuing JWTs that last 30 days with no way to revoke them.

Do this instead

Use short access tokens plus a refresh token you can delete, or simply use sessions.

Your mission

Build both and compare

~45 min

Quick check

A user's laptop is stolen. With which approach can you log them out everywhere right now?

Go deeper

  1. 1Implement a simple session-based login, then a token-based one, and compare the code.
  2. 2Learn why token-based auth is often preferred for APIs consumed by separate frontend apps.
  3. 3Understand sessions need shared storage (Redis) once you run multiple backend instances.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge