Script Valley
JWT & Session Auth: Deep Dive
JWT Deep DiveLesson 2.5

JWT revocation strategies: blocklist and short TTL tradeoffs

stateless revocation problem, token blocklist in Redis, jti claim, logout implementation, short TTL as revocation substitute, hybrid approaches

JWT Revocation Strategies

JWT Revocation Strategies

JWTs are stateless โ€” the server stores nothing. So how do you invalidate one before it expires? This is the hardest JWT problem.

Option 1: Short TTL + accept the gap. Use 5โ€“15 minute access tokens. A stolen token is valid for at most 15 minutes. For most apps, this risk is acceptable. Pair with refresh token rotation so logout invalidates the refresh token, stopping new access tokens from being issued.

Option 2: Token blocklist. Store revoked token IDs (the jti claim) in Redis with a TTL matching the token's remaining lifetime. On every request, check the blocklist.

// Add jti when signing
const token = jwt.sign(
  { sub: user.id, jti: crypto.randomUUID() },
  SECRET,
  { expiresIn: '1h' }
);

// In verify middleware
const payload = jwt.verify(token, SECRET, { algorithms: ['HS256'] });
const revoked = await redis.get(`blocklist:${payload.jti}`);
if (revoked) return res.status(401).json({ error: 'Token revoked' });

// On logout
await redis.set(`blocklist:${payload.jti}`, '1', 'EX', remainingTTL);

The blocklist approach reintroduces state โ€” you now depend on Redis. At that point, you are essentially doing sessions with JWT syntax. This is fine if revocation is required, but understand the architectural cost before choosing it.

JWT revocation strategies: blocklist and short TTL tradeoffs โ€” JWT Deep Dive โ€” JWT & Session Auth: Deep Dive โ€” Script Valley โ€” Script Valley