JWT logout relies on establishing control over token revocation through blacklisting, versioning, or refresh token invalidation, each with its own trade-offs in complexity and security.
Because JWTs are stateless—once issued, they remain valid until they expire—logging out a user is not a built-in feature. There is no automatic way to invalidate a JWT on the server when a user clicks "logout". Therefore, logout must be implemented by introducing some state that the server can check. This involves storing a record of invalidated tokens or rotating a user's key to deactivate old tokens.
When a user logs out, their JWT (specifically its unique identifier, jti) is added to a blacklist (e.g., in Redis). The server then checks this list on every authenticated request. If the token is blacklisted, access is denied. This approach allows instant revocation, but it adds a database check per request, compromising statelessness.
A "version" number (or timestamp) is stored in the user's record (in-memory cache or database). This version is embedded into the JWT payload during token issuance. On logout, the version number is incremented. For subsequent requests, the server compares the JWT's version with the current stored version; a mismatch invalidates the token. This avoids storing each individual token, but still requires a quick lookup per request.
In this pattern, the access token (short-lived, e.g., 15 minutes) is validated statelessly, while the refresh token (longer-lived) is stored on the server. On logout, the server simply deletes or revokes the refresh token. The access token is allowed to expire naturally. This is the most common approach, balancing security and performance.