Best of 2021

Best of 2021 – How to Revoke JSON Web Tokens (JWTs)

As we close out 2021, we at DevOps.com wanted to highlight the most popular articles of the year. Following is the seventeenth in our series of the Best of 2021.

One of the most common questions about JSON Web Tokens (JWTs): Once they’re issued, how can they be revoked?

What Are JWTs?

JSON Web Tokens are portable, industry-standard identity tokens. They are issued after a login request by a central identity server and used to identify and credential a user and grant access to resources. They can be presented by clients such as browsers and external programs. Applications and APIs can examine them to ensure the caller is properly authenticated and authorized.

The Challenges Involved

One of the most common questions is how to revoke them. The problem is that once they are issued, no further communication is needed with the identity server. That’s one major benefit of JWTs decentralization.

Let’s say you use RSA public/private key signing for secure data transmission. After the IdP signs a JWT using the private key, any service that has the public key can verify the integrity of the token.

Let’s use the Todo-Backend API as an example. The architecture might look something like this:

Now, Todo-Backend can use JWT and the public key to verify the user’s ID and other attributes, and then use that ID to perform operations on that user’s data. Once the JWT has been issued, Todo-Backend doesn’t communicate with the identity provider at all. As a result, if an administrator has locked or deleted that user’s account in the identity provider, Todo-Backend won’t know about it.

Managing Revocations Using a Distributed Event System

The most common way to revoke access to resources protected by a JWT involves setting its duration to a short period of time and revoking the refresh token so that the user can’t generate a new token. This does not revoke the JWT per se; it does solve the root issue, which is to limit access.

In other words, you can set the JWT’s expiration duration to a short period (e.g., anywhere from a few seconds to, say, ten minutes) and set the refresh token’s expiration duration to a longer period (e.g., a two-week or two-month window).

During the normal flow, the Todo API would accept the JWT until it expires, at which time access would be denied. At that time the client could present the refresh token to the identity provider, which would send a new JWT to the client. That new JWT would be valid for another ten minutes.

An administrator can, at the identity provider, revoke the refresh token at any time. Any subsequent request for a new JWT by a client holding that refresh token would fail and access to the Todo API would be lost.

However, while ten minutes isn’t long, this timeframe still comes with risks.

One strategic way to handle this challenge is to set up a distributed event system that notifies services when refresh tokens have been revoked. Upon receiving this event broadcast, backends/services would update a local cache that lists users with revoked refresh tokens. After a JWT is verified, this cache would then be checked to determine whether or not access should be revoked.

This distributed event method truly revokes the JWT, rather than simply waiting for it to expire, as mentioned above.

An Example of Revoking JWTs

Here’s a sample solution that provides support for events and webhooks that can be used to implement this revocation strategy. In this example, when a user logs out or has their refresh token otherwise revoked, a jwt.refresh-token.revoke event is emitted. This includes the user ID and the application for which the revocation occurred. It also includes the JWT lifespan for this application (in the below case, 600 seconds). Any JWT for this user that was issued before 600 seconds from the point in time when this event was received is thus revoked.

For example:

  • User logs in, and JWT ‘abc’ is issued at 1:11pm. JWT is good until 1:21
  • User logs out at 1:15. Entry is added stating that any JWT for this application and user expiring before 1:25 is revoked.
  • Application tries to use JWT ‘abc’ at 1:16. Todo-Backend does not deliver data because this JWT is on the denylist.
  • User logs in, and a new JWT ‘def’ is issued at 1:18. JWT is good until 1:28.
  • Application tries to use JWT ‘def’ at 1:19. Todo-Backend delivers data because this JWT is good until 1:28 and is therefore not on the denylist.

What you need to do is write a simple webhook that will receive this event and inform JWTManager that the refresh token for applicationId for this user has been revoked.

JWTManager maintains a list of user IDs whose JWTs are revoked. You could also use JWT IDs (the `jti` claim), which, in some cases, might be simpler. JWTManager also launches a thread to clean up the cache to remove expired users and avoid running out of memory.

For each API call, in addition to all the other checks that should be performed against a JWT (verifying the signature, expiration, issuer and so on), the backend needs to check validity with JWTManager.

As a final step, configure the webhook:

The Revocation Process, Simplified

Using the process described above, you can revoke a user’s refresh token and broadcast the event using a webhook. The webhook receivers then update JWTManager, which will render JWTs for that user unusable.

The good news is that you can use a webhook and event system to build this feature into your application quickly. You can also write JWTManager implementations into Java, Node and other client libraries for future use. Other languages, such as Ruby, have denylist implementations already written.

Ultimately, all that’s required are the use of refresh tokens, an API that enables revocation of refresh tokens and a system for distributing the revocation event. This solution should work well with most systems, even large systems with numerous backends.

Brian Pontarelli

Brian Pontarelli is a successful technology entrepreneur currently focused on solving login, registration, and user management challenges. Brian works with startup to Fortune 500 organizations struggling to address the complexity of secure CIAM as their businesses requirements evolve and user base scales from a handful of users to millions. He has an extensive knowledge of coding strategies as well as a hands-on understanding of the business needs of growing companies. Before Brian bootstrapped both FusionAuth and its sister company CleanSpeak, he studied computer engineering at the University of Colorado, Boulder. After graduating, he solved complex technology challenges for companies like Orbitz, BEA, US Freightways, XOR and Texturemedia.

Recent Posts

Valkey is Rapidly Overtaking Redis

Redis is taking it in the chops, as both maintainers and customers move to the Valkey Redis fork.

14 hours ago

GitLab Adds AI Chat Interface to Increase DevOps Productivity

GitLab Duo Chat is a natural language interface which helps generate code, create tests and access code summarizations.

19 hours ago

The Role of AI in Securing Software and Data Supply Chains

Expect attacks on the open source software supply chain to accelerate, with attackers automating attacks in common open source software…

1 day ago

Exploring Low/No-Code Platforms, GenAI, Copilots and Code Generators

The emergence of low/no-code platforms is challenging traditional notions of coding expertise. Gone are the days when coding was an…

2 days ago

Datadog DevSecOps Report Shines Spotlight on Java Security Issues

Datadog today published a State of DevSecOps report that finds 90% of Java services running in a production environment are…

3 days ago

OpenSSF warns of Open Source Social Engineering Threats

Linux dodged a bullet. If the XZ exploit had gone undiscovered for only a few more weeks, millions of Linux…

3 days ago