Skip to content

JWT Revocation — Complete Strategies for Invalidating Tokens Before Expiry

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about JWT Revocation. We cover key concepts, practical examples, and best practices to help you master this topic.

JWT revocation is the ability to invalidate tokens before their natural expiry, trading off some statelessness for the ability to respond to security events immediately.

What You'll Learn

All JWT revocation strategies, their trade-offs, and how to combine them for defense in depth.

Why It Matters

Stateless JWTs cannot be revoked — they are valid until expiry. For logout, account suspension, or compromised tokens, you need revocation. Choosing the right Strategy affects your architecture, scalability, and security.

Real-World Use

Auth0 uses blacklisting for immediate revocation. GitHub uses short TTL with refresh. Banking APIs use short TTL with per-user invalidation counters. Durga Antivirus Pro combines short TTL (15 min access) with Redis blacklisting for emergency revocation.

flowchart TD
    A["Revocation Strategy"] --> B["Short TTL\n15 min access"]
    A --> C["Blacklist\nRedis-based"]
    A --> D["Token Families\nRotation tracking"]
    A --> E["User Counter\nGlobal invalidation"]
    B --> F["Simple, stateless"]
    C --> G["Immediate, needs Redis"]
    D --> H["Detect token theft"]
    E --> I["Logout all devices"]
    style A fill:#dbeafe,stroke:#2563eb
    style F fill:#dcfce7,stroke:#16a34a
    style G fill:#fef3c7,stroke:#d97706
    style H fill:#fef3c7,stroke:#d97706
    style I fill:#dcfce7,stroke:#16a34a

Revocation Strategies Comparison

Strategy Speed Complexity State Required
Short TTL + Refresh Delayed (until expiry) Low No (stateless)
Blacklist Immediate Medium Yes (token IDs)
Token Families Immediate (theft detection) High Yes (families)
User Invalidation Counter Immediate Medium Yes (user counter)
Combination Best of all High Yes

Code Example: User-Level Invalidation

import jwt, redis, datetime

r = redis.Redis(decode_responses=True)
SECRET = "your-secret"

def issue_token(user_id):
    """Issue token with the current invalidation counter."""
    counter = r.get(f"user:invalidation:{user_id}") or "0"
    payload = {
        "sub": user_id,
        "inv_counter": int(counter),
        "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=15)
    }
    return jwt.encode(payload, SECRET, algorithm="HS256")

def invalidate_all_user_tokens(user_id):
    """Increment counter — all existing tokens become invalid."""
    r.incr(f"user:invalidation:{user_id}")

def validate_token(token):
    """Validate token, checking invalidation counter."""
    try:
        payload = jwt.decode(token, SECRET, algorithms=["HS256"])
        user_id = payload["sub"]
        current_counter = int(
            r.get(f"user:invalidation:{user_id}") or "0"
        )
        if payload.get("inv_counter", -1) < current_counter:
            return None  # Token was invalidated
        return payload
    except jwt.InvalidTokenError:
        return None

Choosing a Strategy

Scenario Recommended Strategy
User logout single device Short TTL + blacklist the refresh token
User logout all devices User invalidation counter
Account suspension Blacklist + short TTL
Token theft suspected Token families with rotation
High-security API All of the above
Public API, low security Short TTL only

Common Mistakes

1. Relying Only on Blacklisting

Blacklisting requires Redis and adds latency. Use short TTL as primary, blacklist as emergency backup.

2. Not Invalidating Refresh Tokens

Revoking access tokens but leaving refresh tokens valid means the attacker can simply get a new access token.

3. Using Only User Counter Without Expiry

The invalidation counter never decrements. Over years, the counter grows. Use short TTL so counter checks are only needed within the token lifetime.

4. Not Handling Concurrent Sessions

Invalidating all tokens on password change logs out all devices. For some apps this is desired; for others, use per-device tokens.

5. Ignoring the jti Claim

Without jti (unique token ID), you cannot blacklist individual tokens. Always include jti.

Practice Questions

  1. Why is revocation harder with stateless JWTs than with session cookies?
  2. What is the simplest JWT revocation strategy?
  3. How does a user invalidation counter work?
  4. What is a token family and how does it detect theft?
  5. Why should you combine multiple revocation strategies?

Answers:

  1. Stateless JWTs are self-contained and valid without server lookup. Revocation requires adding server-side state (blacklist, counter), partly defeating statelessness.
  2. Short TTL (15 minutes). Tokens expire naturally. Combined with refresh token rotation, this covers most scenarios.
  3. Each token includes the current invalidation counter. Incrementing the counter invalidates all tokens with the old counter value. The server checks the counter on each request.
  4. A token family groups all refresh tokens derived from the same login. When an already-rotated token is presented, it signals theft, and the entire family is revoked.
  5. No single strategy is perfect. Short TTL covers normal expiry, blacklist covers emergencies, rotation covers theft — defense in depth.

Challenge: Implement a multi-layered revocation system: short access TTL (15 min), refresh token rotation with family tracking, user invalidation counter for "logout all," and Redis blacklist for emergency single-token revocation.

FAQ

Can you truly revoke a stateless JWT?

No. Stateless JWTs are valid without server lookup. Revocation requires adding server state (blacklist, counter), making the system partially stateful.

How does GitHub handle JWT revocation?

GitHub uses short-lived tokens (configurable, default 30-90 days) with immediate revocation via blacklisting. They also support token rotation.

What is the cost of checking a blacklist on every request?

Redis lookups take sub-millisecond. Combined with Redis replication and local caching, the performance impact is negligible.

Should I revoke all tokens when a user changes password?

Yes. Password change implies potential compromise. Invalidate all existing tokens and force re-login with the new password.

How do token families detect theft?

Each refresh rotates the token. If an old (already rotated) token is presented, the system detects that someone other than the legitimate client is trying to use it, and revokes the entire family.

Mini Project

Build a comprehensive revocation system with JWT that supports: short TTL with automatic refresh, refresh token rotation with family tracking, user invalidation counter for "logout all devices," and Redis blacklist for emergency revocation of specific tokens.

What's Next

Now complete the JWT Capstone Project — building a complete JWT authentication service with all security features.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro