Should I store JWT tokens in redis?
Asked Answered
C

3

44

I'm building an application with ExpressJS, Mongodb(Mogoose). Application contains routes where user has to be authenticated before accessing it.

Currently I have written a express middleware to do the same. Here with the help of JWT token I'm making mongodb query to check whether user is authenticated or not. but feel this might put unnecessary request load on my database.

should I integrate redis for this specific task?
does it will improve API performance? or should go ahead with existing mongodb approach?

would be helpful if I get more insights on this.

Conlee answered 3/7, 2017 at 16:46 Comment(7)
Why do you need to store the JWT tokens? Isn't JWT is used for stateless authentication where you don't need to store the tokens on the server side, but instead you let clients keep hold of it and you just need to verify the signature to see if the data is authentic. So the benefit of having stateless on the server side is that you don't need to worry about the session related issues, you are doing just opposite to that.Follicle
@Follicle Thanks, understood your point. what is proper way to find user is authenticated or not, 1) if after jwt.verify() returns some valid token (I believe this is enough), 2) or should I take this token and check against with database(I think this is bit expensive) ?Conlee
You can keep the user role and other information in the payload section then you can find out upon verify the token, whether he/she is authenticated. Unauthenticated user just won't have one.Follicle
@Follicle I'm still confuse in one scenario. Suppose we have one user (U1) logged-in and having valid token stored. Now admin person has deleted/deactivated that user (U1). In this case I don't want to allow that user (U1) to access authentic routes. How am I suppose to handle this situation? Is there any way to revoke the JWT tokens based on user info (say user ID) ? or should check against with DB on every request to check whether user is valid/present or not.Conlee
You can create a black/revocation list to manage this type of situation. You can also encode a expiry information into the token's payload.Follicle
Wouldn't maintaining a blacklist be no different than maintaining a whitelist in that case? You'd just be using Redis to say "this token hasn't 'logged out' yet"Exclosure
You may use a Map object as yout JWT cache with tokens as keys and an object with some credentials of interest as values.Principe
W
81

TLDR: If you want the capability to revoke a JWT at some point, you'll need to look it up. So yes, something fast like Redis can be useful for that.

One of the well documented drawbacks of using JWTs is that there's no simple way to revoke a token if for example a user needs to be logged out or the token has been compromised. Revoking a token would mean to look it up in some storage and then deciding what to do next. Since one of the points of JWTs is to avoid round trips to the db, a good compromise would be to store them in something less taxing than an rdbms. That's a perfect job for Redis.

Note however that having to look up tokens in storage for validity still reintroduces statefulness and negates some of the main benefits of JWTs. To mitigate this drawback make the list a blacklist (or blocklist, i.e. a list of invalid tokens). To validate a token, you look it up on the list and verify that it is not present. You can further improve on space and performance by staggering the lookup steps. For instance, you could have a tiny in-app storage that only tracks the first 2 or 3 bytes of your blacklisted tokens. Then the redis cache would track a slightly larger version of the same tokens (e.g. the first 4 or 5 bytes). You can then store a full version of the blacklisted tokens using a more persistent solution (filesystem, rdbms, etc). This is an optimistic lookup strategy that will quickly confirm that a token is valid (which would be the more common case). If a token happens to match an item in the in-app blacklist (because its first few bytes match), then move on to do an extra lookup on the redis store, then the persistent store if need be. Some (or all) of the stores may be implemented as tries or hash tables. Another efficient and relatively simple to implement data structure to consider is something called a Bloom filter.

As your revoked tokens expire (of old age), a periodic routine can remove them from the stores. Keep your blacklist short and manageable by also shortening the lifespan of your tokens.

Remember that JWTs shine in scenarios where revoking them is the exception. If you routinely blacklist millions of long-lasting tokens, it may indicate that you have a different problem.

Wintergreen answered 23/9, 2017 at 2:24 Comment(1)
Instead of storing the entire JWT in redis you can assign jti (JWT ID ) to all the tokens and then store only the id in redis, this gives you a way of revoking compromised tokens without storing the entire JWTAntifederalist
C
6

You can use Redis for storing jwt label. Redis is much faster and convenient for storing such data. The request to Redis should not greatly affect the performance. You can try the library jwt-redis

Campman answered 19/7, 2017 at 7:38 Comment(0)
C
-1

JWT contains claims. you can store a claim such as session : guid and maintain a set in redis for all keys black listed. the key should stay in set as long as the jwt validity.

when your api is hit

  1. verify jwt signature. if tempered stop
  2. extract claims in a list of key value pairs
  3. get the session key and check in redis in blacklisted set
  4. if found, stop else continue
Cabman answered 16/2, 2023 at 16:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.