codetomake.com

How to Invalidate JWT Tokens Without Collecting Tokens - DEV Community

2024.12.12 20:59



Skip to content Log in Create account

DEV Community

Add reaction Like Unicorn Exploding Head Raised Hands Fire Jump to Comments Save Boost Copy link Copied to Clipboard Share to X Share to LinkedIn Share to Facebook Share to Mastodon Share Post via Report Abuse José Pablo Ramírez Vargas

Posted on Dec 5, 2022 • Edited on Dec 8, 2022

How to Invalidate JWT Tokens Without Collecting Tokens

# security # beginners

Today I read this article here at dev.to because it is, in my opinion, a topic everyone should care about.

The author explains well all the points, but did not volunteer what I think is the most practical way to invalidate tokens, so I'll do my best to complement that article here.

Unappealing Proposal

Let's start by looking at what people don't like: Invalidating tokens by blacklisting tokens in a database table. This takes space because tokens can get rather big, it forces you to do an extra check, and your table will just grow and grow.

Well, all but one of those problems can be eliminated.

Proposal

There's a better way to invalidate a JWT, and it is by its creation time.

All JWT's should have the iat claim, issued at . This is the time the token was issued/created. Instead of having a blacklist of tokens in the DB/Redis/Memcached , just have a much smaller list/table with user entries and the minimum date a token can be considered valid for that user. This table will only have a single entry per user. If a user goes through token invalidation multiple times, only the most recent one is important. So the table will asintotically grow to the maximum number of users.

But not only that, records in this table can also be deleted after we know for sure all previously issued tokens (that need blacklisting) have expired, making the table even smaller. This is a simple calculation: If now() - token TTL stored timestamp , then the record can be safely eliminated.

So let's review my promise against the list of problems:

Problem Resolved? Potentially big record size (due to size of token) ✅ Table grows without limit ✅ Extra check (DB or cache call) ❌

It looks like I delivered.

Test Drive The Proposal

User X is an administrator, but you just received an email from your boss asking to demote user X to regular user. So you add the following record to our magic table:

{ "userId" : 123456 , "BlTimestamp" : "2022-12-04T19:27:00Z" } }

Now your Security microservice (or subsystem or whatever), when it receives a request using User X's token issued 30 minutes ago and still valid, will undergo the iat check. "Well, well, well, look who's back asking for stuff, User X trying to be all macho deleting stuff. This token was issued at 2022-12-04T18:58:05Z , and I have a record that says I should not accept tokens from you if issued before 2022-12-04T19:27:00Z . No no no. Here's an HTTP 401 for you. Go re-authenticate."

Much simpler, correct? Let me know in the comments if you would like me to demo this in ASP.Net . Below is a core sample of code for NodeJS .

validateToken : function ( token ) { let verifiedToken = null ; try { verifiedToken = jwt . verify ( token , config . jwt . secret ); } catch ( e ) { console . error ( ' Error verifying token: %o ' , e ); return { valid : false }; } // Standard validation succeeded. Let's see about the iat: const globalInv = jwtInvalidationService . globalInvalidation (); const userInv = jwtInvalidationService . userInvalidation ( verifiedToken . name ); let minimumIat = Math . max ( globalInv , userInv ); if ( minimumIat ) { minimumIat = new Date ( minimumIat ); console . debug ( ' Token subject to minimum issued at verification: %s ' , minimumIat ); const issuedAt = new Date ( verifiedToken . iat * 1000 ); if ( issuedAt minimumIat ) { console . warn ( " Token issued at %s for user %s is not acceptable. " , issuedAt , verifiedToken . name ); return { valid : false }; } } return { valid : true , token : verifiedToken }; }

NOTE : I know this extract may not make complete sense because there are things here that aren't obvious. For example, what's inside the token, or how the jwtInvalidationService works or the mechanism as to how to add invalidations is all missing from the code snippet. Make sure to follow me if you don't want to miss an upcoming article with the full project sample, which is about 200 lines of code.

Global Invalidation

The same table and mechanism works to invalidate every single token out there. Just add a blacklist timestamp with no user ID association. Then simply make sure any token you receive was issued after this time. If you ever globally invalidate, the table can actually be truncated, leaving only the global record since the global invalidation will supersede all existing per-user blacklist records, keeping the table small.

More Stuff

You can get more creative with this thing, if needed. You could evolve this model to account for token invalidation of only a particular security group by reviewing the list of roles in the claim (token) or database data. The sky is the limit, folks.

Happy coding!

Top comments (27)

Subscribe José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 Dec 7 22 Copy link Hide

Hi. For most implementations where the size of the table doesn't usually exceed 100 records, I would run cleanup at the same time I do querying. Yes, I would be violating the idempotency of the "Get" nature of the operation in favor of a simplified architecture.

If you don't like that, or if the average number of records makes it so that the invested time in cleanup definitely takes a toll out of using the table values, then spin up a background service that does this cleanup every X minutes.

Also take the opportunity to clean up every time you globally invalidate, and every time a per-user invalidation takes place. Global invalidation cleanup is trivial (empty the table, then just leave the global record); per-user invalidation cleanup would be a DELETE statement with the WHERE condition set to what the paragraph describes as being the condition.

5 likes Like Reply y y y Follow Joined Sep 17, 2023 Sep 17 23 Copy link Hide

Hey! I like this approach, but I just can't figure out how to manage multiple tokens. So, for my understanding, this is the situation I have in mind:

(sorry I didn't have time for fancy graphics)

If the "BlTimestamp" is set to the date when User X logs out in Browser A, then everything's fine if that user continues in that browser.

But if User X opens up Browser B just a few minutes after logging in using Browser A, then I find this problem:

After the User X logs out in Browser A, the requests in Browser B would be denied because I would use the most recent invalidation date (when the user logs out), which should invalidate only token for Browser A.

Now, if the "most recent [token invalidation]" were to be the "exp" of token for Browser B, then any request after User X logs out Browser A, would no longer be unauthorized.

I'm not saying the article is wrong, I'm just confused here.

4 likes Like Reply José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 Sep 17 23 Copy link Hide

Hello!

Logging out from a browser window should be limited to forgetting the token being used by that window and invalidation should not come into play.

This invalidation system is not meant to support log-out processes. To log out, remove the token from session storage. If you are passing the token in a cookie, then delete the cookie. That should be what the log-out process does.

Use this invalidation system to "log out from all devices" scenarios, or "user X's credentials were compromised, so invalidate all tokens for user X".

Let me know if this clarifies the question.

Question you might ask next: How can I have per-tab/browser window cookies? Not easily. I would generate a random GUID on load, then save it to session storage. This GUID would become part of the log-in data. Then the server sends a cookie whose name is/includes this GUID. Never tried this myself. It most certainly sounds like an interesting challenge.

1 like Like Reply y y y Follow Joined Sep 17, 2023 Sep 17 23 Copy link Hide

Oh, now I got you. It's clear. It makes complete sense in cases where I want to invalidate all tokens from a user.

I'll see how to deal with the question you mentioned. Thank you!

2 likes Like Reply 17th_streetCode 17th_streetCode 17th_streetCode Follow Software Developer Location Port Harcourt, Rivers state, and Nigeria. Education Learning Pure and Applied Mathematice Work Software Engineer Joined Nov 20, 2019 Dec 7 22 Copy link Hide

Alright I might be the only one requesting for this but yeah, I want to see the laid out implementation. I will appreciate it.

Node.js, please.

2 likes Like Reply José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 Dec 8 22 Copy link Hide

Hi! I have updated this entry showing the core logic of the iat check. If, like the note below the code snippet says, things don't make complete sense to you, wait for the upcoming article showing the entire project.

2 likes Like Reply 17th_streetCode 17th_streetCode 17th_streetCode Follow Software Developer Location Port Harcourt, Rivers state, and Nigeria. Education Learning Pure and Applied Mathematice Work Software Engineer Joined Nov 20, 2019 Dec 10 22 Copy link Hide

Thank you for the update. Better understood now.

And yes, I'd love an upcoming article detailing the raw implementation of the service.

Ciao

1 like Like Reply José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 Dec 11 22 Copy link Hide

Ok, the full tutorial in NodeJS + Express is out.

Invalidating JSON Web Tokens (JWT): NodeJS + Express

José Pablo Ramírez Vargas ・ Dec 11 ・ 13 min read

#node #javascript #tutorial #beginners 2 likes Like Reply Tony Tony Tony Follow MEANstack developer Location Onitsha, Nigeria Education Bachelor of Engineering Electrical and Electronic Engiheering Joined Jan 29, 2018 May 16 23 Copy link Hide

Brilliant technique. Thanks for the article

1 like Like Reply José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 May 16 23 Copy link Hide

No problem. I'm now exploring single-spa , if you are interested.

1 like Like Reply Tony Tony Tony Follow MEANstack developer Location Onitsha, Nigeria Education Bachelor of Engineering Electrical and Electronic Engiheering Joined Jan 29, 2018 May 17 23 Copy link Hide

I'm interested. Any link to where you are doing that (github or articles)?

1 like Like Thread José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 May 17 23 Copy link Hide

This series @ hashnode.com, where I hold my blog.

1 like Like Reply azeez azeez azeez Follow Full Stack web devloper 🌎 Freelancer 🖥️ Ready to help 💫 Location Lucknow Work Full stack web developer at Freelancer Joined Aug 7, 2020 Dec 8 22 Copy link Hide

I am following this approach when user change his password so I wanted to user should be logout from all the other devices so its work very well in those scenario when we want to invalidate JWT token.

2 likes Like Reply Iqbal Atma Muliawan Iqbal Atma Muliawan Iqbal Atma Muliawan Follow Joined Jul 15, 2023 Jul 15 23 • Edited on Jul 15 • Edited Copy link Hide

Hi. This is a great article, it is very simple way to blacklist the token, but, what if I have multiple device or platform, let say mobile, desktop, and web, and i want to logout from web, it would be logout from all other device, is it correct ?

1 like Like Reply José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 Jul 15 23 Copy link Hide

As it is shown here, yes. But the beauty of it, is that you can further categorize the blacklisting process. Add an extra column to specify the token types that are to be invalidated. I would used a bitwise enumeration: 1 = web, 2 = desktop, 4 = mobile, etc. If I were to invalidate, I would include the type or types of token invalidated: 3 would mean web + desktop; 7 would mean all (web + desktop + mobile). You probably get the idea.

1 like Like Reply Iqbal Atma Muliawan Iqbal Atma Muliawan Iqbal Atma Muliawan Follow Joined Jul 15, 2023 Jul 16 23 Copy link Hide

yeah i got the idea. Thankyou, i love this approach, and this is more eficient approach so far (for jwt auth)

1 like Like Reply SHUKLA123 SHUKLA123 SHUKLA123 Follow Email [email protected] Education UIET, MDU Work Engineer at MoEngage Joined Dec 10, 2022 Dec 10 22 • Edited on Dec 10 • Edited Copy link Hide

If user want to login with Incognito, and normal tab of browser. We will generate 2 JWTs for him. In my db, we only check the latest JWT which will provide user 401. But expected was 200 because user has loggedIn with two different places. Then, In this case it will fail.

Like Reply José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 Dec 10 22 • Edited on Dec 10 • Edited Copy link Hide

If I am understanding correctly, you are saying: If a user users 2 browsers (or one in regular mode and one in incognito mode), the user will have been issued 2 tokens. Yes, so far so good.

Then you say we invalidate the user's tokens based on creation time, which is what the article is about. For some reason you seem to disagree with both tokens being invalidated. This depends on the chronological order of events, but if you are thinking the following, then yes, both tokens get invalidated:

User logs in from browser A.l User receives a valid token, TokenA . User logs in from browser B. User receives a valid token, TokenB . System administrator invalidates all tokens for this user using the current system time.

With this order of events, both tokens were invalidated. Why are you expecting one token to work?? I guess that's the part I don't understand.

UPDATE : Oh, ok. I re-read your answer. For some reason you are thinking incognito mode is special or something? Why do you think the browser used needs to have special treatment? Why do you think one token has to survive just because it came from X or Y browser in N or M mode? To me, that should not matter at all.

2 likes Like Reply SHUKLA123 SHUKLA123 SHUKLA123 Follow Email [email protected] Education UIET, MDU Work Engineer at MoEngage Joined Dec 10, 2022 Dec 11 22 • Edited on Dec 11 • Edited Copy link Hide

Hi
Lets take example
browser A : User receives a valid token, TokenA with userId 123 and timestamp - 2022-12-04T19:27:00Z.
DB call :
{
userId : 123,
timestamp : 2022-12-04T19:27:00Z
}

Same User gone for second browser to login again

browser B : User receives a valid token, TokenB with userId 123 and timestamp - 2022-12-04T20:27:00Z.
DB call :
{
userId : 123,
timestamp : 2022-12-04T20:27:00Z
}

As per your blog the browser A will logout with the api call which took the JWT have timestamp "2022-12-04T19:27:00Z" because the latest one is with the timestamp - "2022-12-04T20:27:00Z". But the user has not logout from any of the browser which will effect the user experience as he logout without any actual logout performed by the user.

How we can support multiple login of the same user with different browser or laptops etc.

2 likes Like Thread José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 Jul 15 23 Copy link Hide

Hi. For some reason I missed this comment. Apologies.

You seem to be thinking that issuing a token automatically invalidates previous tokens. This is only true if you program your system to work like this. At no point in the article do I say that the act of issuing a token necessarily invalidates all previous tokens for the user. I guess that's the misunderstanding we have here.

To me, if a user wants to have two windows open, then by all means, have them open. I'll gladly issue two independent tokens as long as the user can properly authenticate from both browser windows.

1 like Like Reply Gulshan Aggarwal Gulshan Aggarwal Gulshan Aggarwal Follow Software Engineer @Zura Ventures Email [email protected] Location Alwar Education Rajasthan Technical University Kota Work Developer Joined Jul 4, 2020 Dec 5 22 Copy link Hide

Yes, Iat check is a very good approach

2 likes Like Reply Vagner Wentz Vagner Wentz Vagner Wentz Follow Location Foz do Iguaçu, Brazil Work Software Engineer at self-employed Joined Sep 17, 2020 Apr 6 Copy link Hide

You could make an example using ASP.NET what do you think?

1 like Like Reply José Pablo Ramírez Vargas José Pablo Ramírez Vargas José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022 Apr 7 Copy link Hide

Hello. I'll try to make some time for this, but I'm currently a bit swamped. Might take some time. If you're in a hurry, best to study the NodeJS + Express example and apply the same logic in C#.

1 like Like Reply View full discussion (27 comments) Code of Conduct Report abuse

For further actions, you may consider blocking this person and/or reporting abuse

Read next

SEMANTIC HTML AND ACCESIBILITY

felix kagecha - Nov 6

Python NumPy Tutorial for Beginners: Learn Array Creation, Indexing, and More

Arum Puri - Nov 7

How Does Machine Learns (Intro to Machine Learning)

Prakhar Khandelwal - Nov 6

Weight Decay s Critical Role: Theoretical Insights for Better Deep Learning Generalization

Mike Young - Nov 6

José Pablo Ramírez Vargas Follow Location Heredia, Costa Rica Work Senior software developer @ Intel Joined Sep 5, 2022

More from José Pablo Ramírez Vargas

Finally! Cancel Web Workers Work Without Terminating the Worker # webdev # web # workers # beginners Are You in the NPM Package Business? Some Facts I Learned on the Road # npm # javascript # beginners Use JavaScript Blobs to Create Files: The Case of Hundreds of Bulk Import Errors # javascript # webdev # beginners # tutorial

Thank you to our Diamond Sponsor Neon for supporting our community.

DEV Community — A constructive and inclusive social network for software developers. With you every step of your journey.

Home DEV++ Podcasts Videos Tags DEV Help Forem Shop Advertise on DEV DEV Challenges DEV Showcase About Contact Free Postgres Database Guides Software comparisons Code of Conduct Privacy Policy Terms of use

Built on Forem — the open source software that powers DEV and other inclusive communities.

Made with love and Ruby on Rails . DEV Community © 2016 - 2024.

We re a place where coders share, stay up-to-date and grow their careers.

Log in Create account