Token Revocation

Last updated

This page explains what RevokeJWT() does at logout, how the blacklist takes effect, and when nothing gets revoked.

Revocation Flow

Step Action
1 Resolve the Refresh ID: refresh_id argument → X-Refresh-ID header → refresh cookie; return immediately if none
2 Clear the access and refresh cookies
3 Read refresh:<id>; stop if it does not exist
4 Shorten the TTL of refresh:<id> to 5 seconds
5 Write revoke:<access_token> with value "1" and TTL accessTokenExpires

How the Blacklist Takes Effect

The first thing VerifyJWT() does is look up revoke:<access_token>; on a hit it returns a guest (isError: false) without checking the signature. The blacklist TTL equals the Access Token lifetime, so the entry disappears once the token would have expired anyway.

When Nothing Is Revoked

Situation Result
The request carries no Refresh ID Returns immediately: cookies are not cleared and nothing is blacklisted
The refresh data is already gone from Redis Cookies are cleared, but the Access Token is not blacklisted and keeps passing verification until it expires
Redis error Logged with console.error, not thrown

To guarantee revocation, clients should send both the Access Token and the Refresh ID.

Example

import { Request, Response } from "express";
import { JWTAuth } from "@pardnchiu/jwt-auth";

export async function logout(req: Request, res: Response) {
  try {
    await JWTAuth.RevokeJWT(req, res);
    res.json({ message: "Successfully logged out" });
  } catch (err) {
    // Throws only when not initialized
    res.status(500).json({ error: (err as Error).message });
  }
}

Related: Redis Keys, Verification Results

中文