I'm working on an API using Node and Express, with a Mongo database. My users can authenticate using a route, and they get a JWT in exchange.

I want to implement a security mechanism to protect said tokens. Namely, I want the tokens to auto-revoke when a user changes their password, and provide a "Revoke all apps" button, that would invalide all created tokens.

To do so, I added a nonce in the JWT body, which is a random v4 UUID. When the user changes their password or click the button, a new UUID is generated, causing a de-facto revocation of all tokens - since the JWT's body won't match what's coming from the database.

Is this a good approach? I can't think of a way this would be broken, is there anything I overlooked?

  • Do you check the nonce from the JWT against the database on every access? – Sjoerd Mar 2 '17 at 12:31
  • Yes. I know it is not the best in term of performance :x – Rogue Mar 2 '17 at 12:32

Your approach is sound when it comes to security, as long as you (1) use a cryptographically secure PRNG, and (2) don't leak the UUID's somehow. However, it does mean that you have to hit the database to check the UUID at every request. That negates the performance boost you get from using a JWT instead of a traditional session ID.

A minor performance tweak you can do is to instead add revoked tokens to a revocation list that is automatically pruned to remove expired tokens. At every request, you check if the token is in that list. Since a list of all revoked tokens is likely to be shorter than a list of all your users, lookup would be somewhat faster.

And as always the devil is in the details. I am sure there are plenty of mistakes one could make while implementing any of these schemes in code, but that level of detail is beyond the scope of your question.

  • All right. The PRNG used in my uuid package was audited apparently (which is amazing when you consider it's a free npm package), so i'm good in that regard. I will give your idea a shot, sounds like it would indeed be faster. Thanks ;) – Rogue Mar 2 '17 at 12:51

As Anders said, you will need to hit database on every request. Along with an optimization he is proposing with a list without expired tokens, you could implement that list as a bloom filter in memory. That way you will need to hit the database only in case of "Maybe" answer and the performance would be much greater.

  • This is not an answer to the question. – Sjoerd Mar 2 '17 at 13:49
  • A proper answer to a question was given by Anders. I wanted to add yet another method how to improve performance even more. Since I can't comment, the only way I could do that is by adding a new answer. I upvoted his answer to be above mine for clarity. The idea is to share knowledge and help others. Don't understand the need to downvote mine but if it makes you happy... – Marko Vodopija Mar 2 '17 at 13:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.