DEV Community

Cover image for How to invalidate a JWT using a blacklist

How to invalidate a JWT using a blacklist

Tosin Moronfolu on March 08, 2021

This article is going to show you how to invalidate JWTs using the token blacklist method. The token blacklist method is used when creating a logou...
Collapse
 
bartosz_io profile image
Bartosz Pietrucha

If you are using JWT, you want your authorization system to be stateless, right? 🙂. When you introduce blacklisting, you make your authorization stateful! What sense does it make?

This ends up maintaining the list of "logged out", so why not maintain the list of "logged in" and DO NOT use a self-contained token (that exposes the content to anyone), but an opaque token (like session-id) and manage the session on the server. Server-side sessions are by design more secure and logging out isn't any problem.

TL; DR: Blacklisting stateful tokens does not make sense (despite the hype around JWT and cool blacklisting "technique", which probably is fun in developing 🤷‍♂️).

Collapse
 
chukwutosin_ profile image
Tosin Moronfolu

Thank you for your feedback. You have a point, I use sessions also and it works as you've said. There are many ways to go about things, that's how code works, there isn't one way to it. I'm just sharing my knowledge, I didn't say this is the best way or most secure to go about it. Sessions have their flaws as do JWTs, it's just another way. You have your opinion and I'm happy you shared it. Thank you again.

Collapse
 
bartosz_io profile image
Bartosz Pietrucha

What are the flaws of sessions (in comparison to this "JWT blacklisting")? I am not sure I understand your point.

Collapse
 
meatboy profile image
Meat Boy

Great article :) JWT is an awesome topic.
Protip: you can use pub/sub model of Redis to notify the app about new tokens. However, the main JWT has to be stateless like you mention and possible to verify without additional calls so a better approach is to blacklist refresh tokens and make general token live very short.

Collapse
 
chukwutosin_ profile image
Tosin Moronfolu

True, this is another way to go about it. Thank you for the feedback

Collapse
 
bartosz_io profile image
Bartosz Pietrucha

Hi there! So you were maintaining a "small" list of invalidated tokens that still hadn't expired? If yes, did this approach include periodical scanning for expired tokens? Was this really advantageous compared to regular sessions with opaque tokens?

 
bartosz_io profile image
Bartosz Pietrucha • Edited

Interesting case. So this was implemented for long-lived API tokens (order of months)? This must have been a very detailed design process for such an architecture, haven't been?

I believe you had scalability challenges to tackle! Just curious: standard OAuth with rotating refresh tokens was not feasible?

Was the ratio between active long-lived API tokens (many) and invalidated ones (few) one of the deciding factors?

Collapse
 
iamdoctorj profile image
Jyotirmaya Sahu • Edited

But then we need to scan the redis store at some intervals to ensure removal of expired tokens.

Collapse
 
chukwutosin_ profile image
Tosin Moronfolu

You could If you want to, but it would be redundant as the expiry date works automatically to ensure it is removed at the set date. Since the expiry date is the same as the one on the token itself, I don't think there is need to check at intervals anymore

Collapse
 
iamdoctorj profile image
Jyotirmaya Sahu

Yes, correct. But, my point is the expired tokens would pile up eventually consuming a significant part of the store memory at some point of time.

Thread Thread
 
chukwutosin_ profile image
Tosin Moronfolu

True, thank you for the feedback.

Collapse
 
hessman_ profile image
Anthony Domingue • Edited

I think it is not a good idea to add a JWT token to a denylist as it is encoded in base64... You can add "==" to the end of your token to bypass the denylist check and login.

Collapse
 
chukwutosin_ profile image
Tosin Moronfolu

That's if the user somehow gets access to the token and sends it with a request, which is very hard expect they're some hacker or something. And adding extra characters to the end of the token will make sure it's invalid and the verify token middleware checks for that.

If I didn't get you right, please explain.

Collapse
 
hessman_ profile image
Anthony Domingue • Edited

The token is in the header "Authorization" right ? Any user can update the Authorization token in the request. Maybe it's not easy for everyone but it is possible.
JWT is encoded in base64, but in base64 you can add padding with "=" without changing the encoded message. "Hi dev.to !" in base64 is "SGkgZGV2LnRvICE=" but also "SGkgZGV2LnRvICE==" or "SGkgZGV2LnRvICE===".
So if you check the encoded token in the denylist you can just add "=" at the end of the token to bypass the denylist and use the token without changing the decoded value.
Here is the RFC for the base64: tools.ietf.org/html/rfc4648

Thread Thread
 
chukwutosin_ profile image
Tosin Moronfolu

Oh wow, didn't realize this. Thank you for sharing. Will check it out.

 
bartosz_io profile image
Bartosz Pietrucha

Interesting! What if these global development teams didn't check against this JSON file? Just thinking aloud about the practical perspective. Was there any mandate on this?

 
bartosz_io profile image
Bartosz Pietrucha

Great use case! What a scale!

 
chukwutosin_ profile image
Tosin Moronfolu

Thank you for this, I appreciate it!

Collapse
 
chukwutosin_ profile image
Tosin Moronfolu

Amazing, would definitely look into. Thank you!