Portuguese English German

Simple Json Web Token (JWT) Revocation

Disclaimer: When implementing login functionality for web applications, it is recommended to use stateful tokens. These tokens are opaque, meaning they do not contain any user information. They are not susceptible to weak cryptographic algorithms or misconfiguration issues like JSON Web Tokens (JWT). Additionally, stateful tokens can be easily revoked since they are stored in a server-side database. On the other hand, JWTs are better suited for machine-to-machine communication. However, if you still require JWT revocation in your implementation, you can utilize a tool like Redis to verify and reject a specific JWT. If you're interested in exploring alternative revocation methods, please continue reading.

The good part of the web is that there are a lot of content out there so I don't need to reinvent the wheel to explain what is the Json Web Token (JWT) concept. You should look at this article before proceed.

Now supposing that you're familiar with JWT, I'd like to discuss one on its concerns: revocation. In the former model, stateful sessions, you can just wipe all session entries in your database or file system and it's done. But how do you revoke tokens that are out of your control?

There is some built-in attribute for that, "exp", which will help to define if the token is expired or not, but this is not revocation. One possible way is to use something like refresh tokens, but you need to keep track of the token ID to verify which is valid and which is not.

I think that I had a better idea. Instead of managing token IDs, you can just store a hash of the user's already hashed password and store it in the payload. After every authentication attempt, you check the payload's hash with the hash of user's password hash.

This way when the user change his password, all previous JWTs won't work. That's the gotcha that I thought. So, let me show you the JWT generation code in ruby to give you more intuition about what I just wrote:

require 'jwt'
require 'openssl'
require 'securerandom'

SECRET = SecureRandom.random_bytes(20)
@user = User.first
payload = {
    :data     => @user.account_id,
    :authdata => Digest::SHA256.hexdigest(@user.encrypted_password),
    :sub      => "Session",
    :exp      => (Time.now + 1.week).to_i
token = JWT.encode payload, SECRET, 'HS256'

Additional Notes

I just found the article I don’t see the point in Revoking or Blacklisting JWT, which the author says that there is no point in revoking JWT because you lose the 'federation' benefit, that is, the benefit of not asking the issuer if the token is valid or not, as it is self-described and includes an expiration time. That sounds very reasonable for the OAuth context mentioned in the article. It even reduces the call to database implied in this article to verify if the user password as changed. However, that is not the only possible application of JWTs. Revoking json web tokens is a good idea in certain contexts, for example when you don't need the federation benefit as in my example above when I switched the previous stateful session that stores the session ID in the browser's cookie for a JWT stored in localstorage.

Share on Twitter Share on Facebook Share on LinkedIn Share on Hacker News

Popular Posts