Revoke millions of JWTs instantly by moving away from pure statelessness and introducing a lightweight, stateful revocation layer using a JTI-based blacklist, versioning, or a combination, all powered by a high-performance distributed cache.
Due to their stateless nature, JWTs cannot be revoked directly. However, you can build a system that achieves instant invalidation by adding a fast, highly scalable stateful layer. The core principle is to avoid storing all valid tokens; instead, store only the exceptions—the tokens you need to revoke. The most effective strategy for instant, large-scale revocation combines a JTI-based (JWT ID) blocklist with user-level versioning, both backed by a high-performance distributed cache like Redis.
The most performant way to minimize the impact of a required revocation is to reduce the token's natural lifespan. By using short-lived access tokens (e.g., 5-15 minutes), you ensure that even if you don't instantly revoke it, the window of vulnerability is tiny. This is often paired with a refresh token rotation strategy, where each refresh request issues a new refresh token and invalidates the previous one. This detects token theft (e.g., if an attacker uses an old refresh token) and allows you to revoke the user's entire session.
For scenarios requiring immediate revocation, you need a dedicated system. This system does not replace JWTs but supplements them with a fast, reliable source of truth for invalidation. The architecture below, built on JTI-based blocklisting, is the industry standard.
JTI (JWT ID): Every issued JWT must contain a unique jti (JWT ID) claim in its payload. This acts as the primary key for an individual token. Use a cryptographically secure random value (e.g., UUID v4).
Revocation Blocklist (e.g., Redis): Stores the identifiers (jti) of revoked tokens as keys, with a TTL equal to the token's remaining lifespan. On each API request, the validation logic performs a low-latency check against this blocklist, rejecting tokens that have been revoked. Implement a Bloom filter on validation nodes to reduce unnecessary checks.
User-Level Versioning (for Bulk Revocation): To instantly revoke all tokens for a user (e.g., password change, account deletion), maintain a version number or timestamp for each user in Redis. Include this version in every JWT during issuance. On each request, compare the token's version with the user's current version; if they don't match, the token is rejected. This is a single, atomic update that invalidates millions of tokens instantly.
Atomic Updates: All revocation operations must be atomic. Incrementing a user's version or adding a JTI to the blocklist should complete instantly, guaranteeing that the next request using a revoked token will be rejected.
Cost: This approach introduces state and requires a highly available and fast data store like a Redis cluster.
Network Latency: Each request now incurs one or two extra round trips to check the revocation layer, adding a small, predictable latency. With local Redis, this can be under 1ms, which is acceptable for most systems.
Performance: JTI blocklists can grow large, but the combined use of TTLs, versioning (which invalidates many tokens at once), and Bloom filters keeps the system efficient and scalable.
To revoke millions of JWTs instantly, you must abandon the idea of pure statelessness and embrace a small, highly scalable stateful component. The combination of short-lived tokens to limit the impact, a JTI-based blocklist for granular, per-token control, and user-level versioning for mass, instantaneous revocation is the most robust and performant strategy used in production systems today. This architecture provides an instant 'kill switch' for any token or user, while keeping the latency impact on API calls minimal.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience