← All articles · April 15, 2026 · fmt.hjlabs.in

JWT vs Session Auth: When to Use Which (with examples)

"Should I use JWT or session cookies for auth?" remains one of the most-asked questions in web development. The internet is full of contradictory advice. This is the practitioner's answer based on what actually works in 2026.

The two approaches in one paragraph

Session auth: on login, server creates a record in a database/Redis with a random session ID. Sends the ID to the client as an HTTP-only cookie. On every request, server looks up the session in storage to identify the user.

JWT auth: on login, server creates a signed token containing the user's claims (id, role, expiry). Sends the token to the client (cookie or localStorage). On every request, server verifies the signature and reads claims from the token — no database lookup needed.

The fundamental tradeoff

Session auth is easy to revoke (delete the row in Redis) but requires a network/cache round-trip per request. JWT auth is stateless and fast but hard to revoke before expiry.

When session auth wins

  1. You need instant logout across all devices ("revoke this user now")
  2. You can afford a Redis lookup per request (latency <1ms within the same datacenter)
  3. Your auth state changes frequently (role changes, permission changes mid-session)
  4. You're building a traditional monolithic web app with server-side rendering

When JWT auth wins

  1. You have a distributed/microservices architecture — services don't share a session store
  2. You serve mobile or third-party API clients where cookies are awkward
  3. You can tolerate revocation latency (10-15 minutes typical)
  4. You're optimising for edge runtime auth (Cloudflare Workers, Vercel Edge) — no Redis

The hybrid (best of both)

Most production systems in 2026 use a hybrid:

Session auth example (Express + Redis)

// Session middleware
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: process.env.SECRET,
  cookie: { httpOnly: true, secure: true, sameSite: 'lax' }
}));

// Login
app.post('/login', async (req, res) => {
  const user = await authenticate(req.body);
  req.session.userId = user.id;
  res.json({ ok: true });
});

JWT example (edge runtime)

// On login
import { SignJWT } from 'jose';
const token = await new SignJWT({ uid: user.id, role: user.role })
  .setProtectedHeader({ alg: 'HS256' })
  .setExpirationTime('15m')
  .setIssuedAt()
  .sign(new TextEncoder().encode(secret));

// On every request
const { payload } = await jwtVerify(token, secret);
const userId = payload.uid;

JWT security pitfalls (the famous list)

  1. Storing JWTs in localStorage. XSS-vulnerable. Use HTTP-only cookies.
  2. The "alg: none" attack. Some libraries accept tokens with alg: none. Always specify algorithm in verifier config.
  3. Algorithm confusion (RS256 vs HS256). If verifier accepts both, attacker can sign with the public key. Lock to one algorithm.
  4. Long expiries. 30-day JWTs can't be revoked. Keep access tokens at 15 minutes.
  5. Leaking sensitive data in payload. JWT claims are base64-encoded, not encrypted. Don't put PII or secrets in claims.

Decode and inspect tokens

Use our JWT decoder to inspect any token — view header, payload, expiry, and verify signature structure. Essential for debugging.

Refresh token rotation

Best practice in 2026: refresh token rotation. Each time a refresh token is used, issue a new one and invalidate the old. If the old token is reused, that's evidence of theft — invalidate the entire family.

The correct boring choice

For most B2B web apps with a single backend, session cookies in Redis are the right answer. Easy to revoke, well-understood, fast on a hot session. Don't reach for JWT to feel modern — reach for it when you actually need statelessness.

For edge runtimes specifically

If you're on Cloudflare Workers or similar, JWT is the path of least resistance. Even then: keep access tokens short (15 min), maintain a small KV-stored revocation list for emergency invalidation.

Bottom line

Sessions are easier to operate. JWTs are easier to scale. Hybrid (short JWT + refresh) is what most production systems converge to. Don't overthink it for an MVP — pick sessions, swap later if needed.

Try the free dev tools suite

15+ tools. 100% client-side. No signup. No tracking.

Browse all tools →

More from the blog