Sessions vs JWT: Choosing an Auth Strategy
9 min read
Sessions vs JWT: Choosing an Auth Strategy
There are two dominant approaches to keeping a user logged in across HTTP requests: server-side sessions stored in a database or in-memory store, and stateless JWTs signed by the server and stored on the client.
Server-Side Sessions with express-session
js
const session = require("express-session");
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days in ms
}
}));
// After login, attach user info to the session
app.post("/login", async (req, res) => {
// ... verify credentials ...
req.session.userId = user.id;
res.json({ ok: true });
});
// Protected route reads from session
app.get("/dashboard", (req, res) => {
if (!req.session.userId) return res.status(401).json({ error: "Not authenticated" });
res.json({ userId: req.session.userId });
});Comparison
- Sessions: easy to revoke (delete the record), require a shared store (Redis) for multi-server deployments, send only a small cookie
- JWT: stateless so they scale horizontally without a shared store, but hard to revoke before expiry without a denylist
- Use sessions when immediate revocation matters (banking, admin panels)
- Use JWT when you need stateless horizontal scaling or cross-service auth (microservices)
Never store JWTs in localStorage — they are readable by any JavaScript on the page and vulnerable to XSS. Prefer HttpOnly cookies with the Secure and SameSite=Strict flags set.
Ready to test yourself?
Practice Express— quiz & coding exercises