Token Revocation Gap
The window between deciding a token should no longer be valid and it actually ceasing to work, which for self-contained tokens is its remaining lifetime.
Self-contained tokens are validated by checking a signature, with no call to the issuer. That is what makes them scalable and it is exactly what makes revocation hard: a resource server has no way to learn that a token was revoked, because it never asks.
So a compromised token, a logged-out session, a disabled account or a role change remains effective until expiry. If tokens last an hour, an attacker with a stolen token has an hour, and a fired employee retains access for the same period.
The approaches, each with a real cost. Short lifetimes with refresh tokens shrink the window to minutes and shift the check to refresh time, which is the standard answer and the right default. Denylists of revoked identifiers restore immediate revocation and reintroduce the shared state that self-contained tokens were adopted to avoid — though a small denylist checked from a local cache is a reasonable compromise. Introspection on every request gives correctness and gives up the scalability entirely.
The decision worth making deliberately: what is the maximum acceptable revocation delay for this system? Fifteen minutes is fine for most internal tools and unacceptable for administrative access to production or for anything where a session must end on a safeguarding decision. Different answers can coexist by issuing different lifetimes per audience.