Invalidating JSON Web Tokens
Solution 1
I too have been researching this question, and while none of the ideas below are complete solutions, they might help others rule out ideas, or provide further ones.
1) Simply remove the token from the client
Obviously this does nothing for server side security, but it does stop an attacker by removing the token from existence (ie. they would have to have stolen the token prior to logout).
2) Create a token blocklist
You could store the invalid tokens until their initial expiry date, and compare them against incoming requests. This seems to negate the reason for going fully token based in the first place though, as you would need to touch the database for every request. The storage size would likely be lower though, as you would only need to store tokens that were between logout & expiry time (this is a gut feeling, and is definitely dependent on context).
3) Just keep token expiry times short and rotate them often
If you keep the token expiry times at short enough intervals, and have the running client keep track and request updates when necessary, number 1 would effectively work as a complete logout system. The problem with this method, is that it makes it impossible to keep the user logged in between closes of the client code (depending on how long you make the expiry interval).
Contingency Plans
If there ever was an emergency, or a user token was compromised, one thing you could do is allow the user to change an underlying user lookup ID with their login credentials. This would render all associated tokens invalid, as the associated user would no longer be able to be found.
I also wanted to note that it is a good idea to include the last login date with the token, so that you are able to enforce a relogin after some distant period of time.
In terms of similarities/differences with regards to attacks using tokens, this post addresses the question: https://github.com/dentarg/blog/blob/master/_posts/2014-01-07-angularjs-authentication-with-cookies-vs-token.markdown
Solution 2
The ideas posted above are good, but a very simple and easy way to invalidate all the existing JWTs is simply to change the secret.
If your server creates the JWT, signs it with a secret (JWS) then sends it to the client, simply changing the secret will invalidating all existing tokens and require all users to gain a new token to authenticate as their old token suddenly becomes invalid according to the server.
It doesn't require any modifications to the actual token contents (or lookup ID).
Clearly this only works for an emergency case when you wanted all existing tokens to expire, for per token expiry one of the solutions above is required (such as short token expiry time or invalidating a stored key inside the token).
Solution 3
This is primarily a long comment supporting and building on the answer by @mattway
Given:
Some of the other proposed solutions on this page advocate hitting the datastore on every request. If you hit the main datastore to validate every authentication request, then I see less reason to use JWT instead of other established token authentication mechanisms. You've essentially made JWT stateful, instead of stateless if you go to the datastore each time.
(If your site receives a high volume of unauthorized requests, then JWT would deny them without hitting the datastore, which is helpful. There are probably other use cases like that.)
Given:
Truly stateless JWT authentication cannot be achieved for a typical, real world web app because stateless JWT does not have a way to provide immediate and secure support for the following important use cases:
-
User's account is deleted/blocked/suspended.
-
User's password is changed.
-
User's roles or permissions are changed.
-
User is logged out by admin.
-
Any other application critical data in the JWT token is changed by the site admin.
You cannot wait for token expiration in these cases. The token invalidation must occur immediately. Also, you cannot trust the client not to keep and use a copy of the old token, whether with malicious intent or not.
Therefore:
I think the answer from @matt-way, #2 TokenBlackList, would be most efficient way to add the required state to JWT based authentication.
You have a blacklist that holds these tokens until their expiration date is hit. The list of tokens will be quite small compared to the total number of users, since it only has to keep blacklisted tokens until their expiration. I'd implement by putting invalidated tokens in redis, memcached or another in-memory datastore that supports setting an expiration time on a key.
You still have to make a call to your in-memory db for every authentication request that passes initial JWT auth, but you don't have to store keys for your entire set of users in there. (Which may or may not be a big deal for a given site.)
Solution 4
I would keep a record of the jwt version number on the user model. New jwt tokens would set their version to this.
When you validate the jwt, simply check that it has a version number equal to the users current jwt version.
Any time you want to invalidate old jwts, just bump the users jwt version number.
Solution 5
Haven't tried this yet, and it is uses a lot of information based on some of the other answers. The complexity here is to avoid a server side data store call per request for user information. Most of the other solutions require a db lookup per request to a user session store. That is fine in certain scenarios but this was created in an attempt to avoid such calls and make whatever required server side state to be very small. You will end up recreating a server side session, however small to provide all the force invalidation features. But if you want to do it here is the gist:
Goals:
- Mitigate use of a data store (state-less).
- Ability to force log out all users.
- Ability to force log out any individual at any time.
- Ability to require password re-entry after a certain amount of time.
- Ability to work with multiple clients.
- Ability to force a re-log in when a user clicks logout from a particular client. (To prevent someone "un-deleting" a client token after user walks away - see comments for additional information)
The Solution:
- Use short lived (<5m) access tokens paired with a longer lived (few hours) client stored refresh-token.
- Every request checks either the auth or refresh token expiration date for validity.
- When the access token expires, the client uses the refresh token to refresh the access token.
- During the refresh token check, the server checks a small blacklist of user ids - if found reject the refresh request.
- When a client doesn't have a valid(not expired) refresh or auth token the user must log back in, as all other requests will be rejected.
- On login request, check user data store for ban.
- On logout - add that user to the session blacklist so they have to log back in. You would have to store additional information to not log them out of all devices in a multi device environment but it could be done by adding a device field to the user blacklist.
- To force re-entry after x amount of time - maintain last login date in the auth token, and check it per request.
- To force log out all users - reset token hash key.
This requires you to maintain a blacklist(state) on the server, assuming the user table contains banned user information. The invalid sessions blacklist - is a list of user ids. This blacklist is only checked during a refresh token request. Entries are required to live on it as long as the refresh token TTL. Once the refresh token expires the user would be required to log back in.
Cons:
- Still required to do a data store lookup on the refresh token request.
- Invalid tokens may continue to operate for access token's TTL.
Pros:
- Provides desired functionality.
- Refresh token action is hidden from the user under normal operation.
- Only required to do a data store lookup on refresh requests instead of every request. ie 1 every 15 min instead of 1 per second.
- Minimizes server side state to a very small blacklist.
With this solution an in memory data store like reddis isn't needed, at least not for user information as you are as the server is only making a db call every 15 or so minutes. If using reddis, storing a valid/invalid session list in there would be a very fast and simpler solution. No need for a refresh token. Each auth token would have a session id and device id, they could be stored in a reddis table on creation and invalidated when appropriate. Then they would be checked on every request and rejected when invalid.
funseiki
Python wrestler, by day. High-fiber eating, app-developing, video game playing being, by night.
Updated on July 08, 2022Comments
-
funseiki almost 2 years
For a new node.js project I'm working on, I'm thinking about switching over from a cookie based session approach (by this, I mean, storing an id to a key-value store containing user sessions in a user's browser) to a token-based session approach (no key-value store) using JSON Web Tokens (jwt).
The project is a game that utilizes socket.io - having a token-based session would be useful in such a scenario where there will be multiple communication channels in a single session (web and socket.io)
How would one provide token/session invalidation from the server using the jwt Approach?
I also wanted to understand what common (or uncommon) pitfalls/attacks I should look out for with this sort of paradigm. For example, if this paradigm is vulnerable to the same/different kinds of attacks as the session store/cookie-based approach.
So, say I have the following (adapted from this and this):
Session Store Login:
app.get('/login', function(request, response) { var user = {username: request.body.username, password: request.body.password }; // Validate somehow validate(user, function(isValid, profile) { // Create session token var token= createSessionToken(); // Add to a key-value database KeyValueStore.add({token: {userid: profile.id, expiresInMinutes: 60}}); // The client should save this session token in a cookie response.json({sessionToken: token}); }); }
Token-Based Login:
var jwt = require('jsonwebtoken'); app.get('/login', function(request, response) { var user = {username: request.body.username, password: request.body.password }; // Validate somehow validate(user, function(isValid, profile) { var token = jwt.sign(profile, 'My Super Secret', {expiresInMinutes: 60}); response.json({token: token}); }); }
--
A logout (or invalidate) for the Session Store approach would require an update to the KeyValueStore database with the specified token.
It seems like such a mechanism would not exist in the token-based approach since the token itself would contain the info that would normally exist in the key-value store.
-
Aaron Wagner about 10 yearsExcellent approach. My gut would be to do a combination of all 3, and/or, request a new token after every "n" requests (as opposed to a timer). We are using redis for in-memory object storage, and we could easily use this for case #2, and then the latency would go WAY down.
-
funseiki about 10 yearsThis coding horror post offers some advice: Keep session bearing cookies (or tokens) short but make it invisible to the user - which appears to be in line with #3. My own gut (perhaps because it is more traditional) is just to have the token (or a hash of it) act as a key into white-listed session database (similar to #2)
-
Stephen Smith almost 10 yearsThis is an interesting idea, the only thing is where to store the version, as part of the purpose of tokens is it being stateless and not needing to use the database. A hard coded version would make it hard to bump, and a version number in a database would negate some of the benefits of using tokens.
-
DaftMonk almost 10 yearsPresumably you're already storing a user id in your token, and then querying the database to check that the user exists / is authorized to access the api endpoint. So you aren't doing any extra db queries by comparing the jwt token version number with the one on the user.
-
DaftMonk almost 10 yearsI shouldn't say presumably, because theres a lot of situations where you might use tokens with validations that don't touch the database at all. But I think in this case its hard to avoid.
-
roundrobin almost 10 yearsUseful article around how invalidate a compromised JWT token: kdelemme.com/2014/05/12/…
-
Matt Way almost 10 yearsThe article is well written, and is an elaborated version of
2)
above. While it works fine, personally I don't see much difference to traditional session stores. I guess the storage requirement would be lower, but you still require a database. The biggest appeal of JWT for me was to not use a database at all for sessions. -
meeDamian almost 10 yearsWhat if user logs in from multiple devices? Should one token be used across them all or should login invalidate all previous ones?
-
Travis Terry over 9 yearsA common approach for invalidating tokens when a user changes their password is to sign the token with a hash of their password. Thus if the password changes, any previous tokens automatically fail to verify. You can extend this to logout by including a last-logout-time in the user's record and using a combination of the last-logout-time and password hash to sign the token. This requires a DB lookup each time you need to verify the token signature, but presumably you're looking up the user anyway.
-
ndbroadbent about 9 years@meeDamian - You could keep a separate jwt version number for each token type, and increment that number to invalid a specific token. For example, your web app token could have a payload like:
"typ":"web","ver":1
, and your mobile app token could be:"typ":"mob","ver":1
. Your user record could have a JSON column namedtoken_versions
, containing:{"web": 1, "mob": 1}
. So each one could be invalidated separately. But yeah, however you do it, you're going to need a database request to check if the token has been invalidated. -
ndbroadbent about 9 yearsReading more about claims - you could probably use the "aud" field for this, and store different versions for each audience.
-
Signus about 9 yearsI think this approach isn't ideal. While it works and is certainly simple, imagine a case where you're using a public key - you wouldn't want to go and recreate that key any time you want to invalidate a single token.
-
stewenson almost 9 yearsI do not see any problem with logging out from all devices / locations as a side effect of the token invalidation. If you "log out" from somewhere, does not it mean that you really just logged out from everywhere? It can be even desirable behaviour. Why would you want to still have acccess on one device and not on another one if you hit that logout button in the first place?
-
Kijana Woodard over 8 years@Signus - using a public key for a secret?
-
Kijana Woodard over 8 years@stewenson - perhaps you logged in on a shared/public device and only want your token removed from there.
-
Signus over 8 years@KijanaWoodard, a public/private key pair can be used to validate the signature as effectively the secret in the RS256 algorithm. In the example shown here he mentions changing the secret to invalidate a JWT. This can be done by either a) introducing a fake pubkey that doesn't match the signature or b) generating a new pubkey. In that situation, it is less than ideal.
-
Kijana Woodard over 8 years@Signus - gotcha. not using the public key as the secret, but others may be relying on the public key to verify the signature.
-
mcont over 8 years@nathan.f77 would it be ok to use the
jdi
claim as a counter (=ver), along withaud
for the device (=typ)? -
OneHoopyFrood over 8 yearsGood thought! To solve the "one device" problem is to make this a contingency feature rather than a logout. Store the a date on the user record that invalidates all tokens issued before it. Something like
token_valid_after
, or something. Awesome! -
Vijay Kumar Rajput over 8 years@nathan.f77 I like suggestion to use "typ":"web" or "typ":"mobile" but as per specification -
The typ (type) Header Parameter defined by [JWS] and [JWE] is used by JWT applications to declare the media type [IANA.MediaTypes] of this complete JWT
. But its also says thatThis parameter is ignored by JWT implementations; any processing of this parameter is performed by the JWT application
So I believe there is no harm to use it by application as you said. -
alexventuraio over 8 yearsHow do you reject the token? Can you show a brief example code?
-
Vanuan over 8 years
if (jwt.issue_date < user.last_pw_change) { /* not valid, redirect to login */}
-
Sergio Correa about 8 yearsWouldn't be even simpler just keeping the token in the database instead of adding extra complexity with version ? The database will be hit anyway. I would prefer not hit the database at all.
-
Ed J about 8 yearsI agree with @SergioCorrea This would make JWT almost as stateful as any other token authentication mechanism.
-
Julian about 8 yearsI don't agree with your answer. Hitting a database does not make anything stateful; storing state on your backend does. JWT was not created so that you don't have to hit the database on each request.Every major application that uses JWT is backed by a database. JWT solves a completely different problem. en.wikipedia.org/wiki/Stateless_protocol
-
Joe Lapp about 8 yearsWhat about the scenario where one person gets up from a computer to let another person use the same computer? The 1st person will logout and expect the logout to instantly block the 2nd person. If the 2nd person is an average user, the client could easily block the user by deleting the token. But if the 2nd user has hacking skills, the user has time to recover the still-valid token to authenticate as the 1st user. It seems that there is no way avoid the need to immediately invalidate tokens, without delay.
-
Joe Lapp about 8 yearsThis is the solution I've been considering, but it has these drawbacks: (1) you're either doing a DB-lookup on each request to check the random (nullifying the reason for using tokens instead of sessions) or you're only checking intermittently after a refresh token has expired (preventing users from logging out immediately or sessions from being terminated immediately); and (2) logging out logs the user out from all browsers and all devices (which is not conventionally expected behavior).
-
Joe Lapp about 8 yearsAnother problem with (3) by itself is that it violates a user's expectation that the account becomes immediately inaccessible at time of logout. A hacker who sits down at the computer right after the user gets up has a chance to recover the still-valid token before it expires, although that may take reading disk sectors.
-
Joe Lapp about 8 yearsA blacklist can be made efficient by keeping it in memory, so that the DB need only be hit to record invalidations and remove expired invalidations and only read at server launch. Under a load-balancing architecture, the in-memory blacklist can poll the DB at short intervals, like 10s, limiting the exposure of invalidated tokens. These approaches allow the server to continue authenticating requests without per-request DB accesses.
-
Ashtonian about 8 yearsYou could handle that with your servrside black list. Which you would have to maintain but it'd be pretty small and only require you to keep the entry in the list for the length of the tokens ttl.
-
Kamil Kiełczewski almost 8 yearsOr you can remove your JWT from sesion/local storage or cookie.
-
NicolasV almost 8 yearsYou don't need to change the key when the user logs out, only when they change their password or -if you provide it- when they choose to log out from all devices
-
Tuomas Toivonen over 7 yearsThis is very bad solution. Main reason to use JWT is it's stateless and scales. Using a dynamic secret introduces a state. If the service is clustered across multiple nodes, you would have to synchronize the secret each time new token is issued. You would have to store secrets in a database or other external service, which would be just re-inventing cookie based authentication
-
Ashtonian over 7 years@JoeLapp I know its a bit old but I updated the answer and I think it'll cover your case.
-
Joe Lapp over 7 yearsThanks @Ashtonian. After doing extensive research, I abandoned JWTs. Unless you go to extraordinary lengths to secure the secret key, or unless you delegate to a secure OAuth implementation, JWTs are much more vulnerable than regular sessions. See my full report: by.jtl.xyz/2016/06/the-unspoken-vulnerability-of-jwts.html
-
Frug over 7 yearsYou can hash the token itself and store that value in redis, rather than inject a new hash into the token.
-
Kerem Baydoğan over 7 yearsput tokens into blacklist and there goes your statelessness
-
Ravinder Payal over 7 yearsUSER ID changing is headache for MYSQL based solutions, as it will be required to change every row in database where user was logged in. instead add facility of account locking perioed as in case of debit/credit cards. Keep the end time of locking period equal to expiry time of token.
-
Rohmer almost 7 years@TuomasToivonen, but you must sign a JWT with a secret and be able to verify the JWT with that same secret. So you must store the secret on the protected resources. If the secret is compromised you must change it and distribute that change to each of your nodes. Hosting providers with clustering/scaling usually allow you to store secrets in their service to make distributing these secrets easy and reliable.
-
Rohmer almost 7 yearsUsing a refresh token is the key to allowing blacklisting. Great explanation: auth0.com/blog/…
-
secondbreakfast over 6 years@Julian can you elaborate on this a little? Which problem does JWT really solve then?
-
Julian over 6 years@zero01alpha Authentication: This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Information Exchange: JSON Web Tokens are a good way of securely transmitting information between parties. Because JWTs can be signed you can be sure the senders are who they say they are. See jwt.io/introduction
-
LIvanov about 6 years@Julian I don't agree with your disagreement :) JWT solves the problem (for services) to have the need to access a centralized entity providing authorization information for any given client. So instead of service A and service B have to access some resource to find out if client X has or has not permissions to do something, service A and B receive a token from X that proves his/hers permissions (most commonly issued by a 3rd party). Anyway, JWT is a tool that helps avoiding a shared state between services in a system, especially when they are controlled by more than one service provider.
-
Rob Evans about 6 yearsLike all the other proposed solutions, this one requires a database lookup which is the reason this question exists because avoiding that lookup is the most important thing here! (Performance, scalability). Under normal circumstances you don't need a DB lookup to have the user data, you already got it from the client.
-
Rob Evans about 6 yearsRequires a db lookup!
-
abbood almost 6 yearsthis isn't an option for apps that have a large existing customer base. Most customers simply don't remember their passwords and force logging them out indiscriminately will hurt user experience
-
M3RS over 5 yearsThis seems to me the best answer as it combines a short-lived access token with a long-lived refresh token that can be blacklisted. On logout, client should delete the access token so a 2nd user can't get access (even though the access token will remain valid for a few more minutes after logout). @Joe Lapp says a hacker (2nd user) get the access token even after it's been deleted. How?
-
catamphetamine over 5 years@LIvanov No, JWT doesn't solve the access managing issue because access info (roles, permissions) is edited in real time and JWT tokens are stateless and can't be edited so they're useless for that purpose. Every time a 3rd party uses Google's token to perform an action on behalf of a user such token must be validated in a database otherwise it would be unrevokable. So a database can not be moved out of the scheme.
-
user2555515 over 5 yearsMost production sites run on more than one server so this solution will not work. Adding Redis or similar interpocess cache significantly complicates the system and often brings more problems than solutions.
-
dvdmn over 5 yearsSame list can be kept in memory (application for c#) and it would eliminate the need for hitting the db for each request. The list can be loaded from db on application start
-
Eduardo about 5 years@user2555515 all servers can be synchronized with the database. It is your choice hitting the database everytime or not. You could tell what problems it brings.
-
user2555515 about 5 yearsOf course it is not the best ! Anyone having access to the db can easily impersonate any user.
-
Yuvaraj V about 5 yearsYou can not logout for invalidating single token. I think this is the worst idea.
-
Peter Lada almost 5 yearsAlso check out
aud
andjti
claims in JWT, you are on the right path. -
Peter Lada almost 5 yearsYes, this. Maybe make a one-to-many relation between the user table and a new (session) table, so you can store meta data along with the jti claims.
-
Chunky Chunk almost 5 years@user2555515 This solution works fine if the token that is stored on the database is encrypted, just like any password stored on the database should be. There is a difference between
Stateless JWT
andStateful JWT
(which is very similar to sessions).Stateful JWT
can benefits from maintaining a token whitelist. -
adnanmuttaleb almost 5 years@TravisTerry Your approach if useful in monolithic apps, but in order to implement it in a microservices app you need all services to either store the user's password and last login or to make requests to fetch them and both are bad ideas.
-
Jingshao Chen over 4 yearsAnother way is to use a random secret for each user, and keep the secret with the user in the database. When a user logout or change password, just change the secret in the database.
-
giantas over 4 yearsAlso from jwt.io/introduction
If the JWT contains the necessary data, the need to query the database for certain operations may be reduced, though this may not always be the case.
-
giantas over 4 yearsSome more detail would suffice
-
Koushik Shom Choudhury over 4 yearsBy this approach, users need to have unique secrets. Not ideal. Anyways, it's a good primitive approach but not practical.
-
Koushik Shom Choudhury over 4 yearsThe purpose of having a refresh token is lost if DB is hit everytime.
-
Tommy Aria Pradana about 4 years@giantas, i think what Mark mean is the signature part. So instead using only single key to sign the JWT, combine it a key that unique for each client. Therefore, if you want invalidate a user's all session, just change the key for that user and if you to invalidate all session in your system, just change that global single key.
-
Daniel Valland about 4 years@TravisTerry I am using a simple token-version counter. Tokens are issued with a token-version integer in the object, and each user has a token_version attribute. The version in the token must match with the user... Whenever i want to invalidate all previous tokens (such as at password change), i simply increment the users token-version... Care to weigh in? The effect is the same, any reason to go for a full hash?
-
IMSoP almost 4 yearsThis can be easily combined with the refresh token approach suggested in a different answer to reduce the number of accesses to the data store.
-
funseiki almost 4 yearsThis is useful for just how to use jwts without db lookups, but how does one enforce a logout? A removal of the
tokenhash
from the db? -
Ebru Yener almost 4 yearsIf you maintain the backlist in the database, you still stay stateless
-
Kerem Baydoğan almost 4 yearsput blacklist into the database and there go your performance and scalability.
-
codeman48 almost 4 years@funseiki Yes. On a user logout the token can be removed from the client and the
tokenhash
changed to a special value. In the "immediate" future all other possible copies become invalid too and hence forcing a re-login. Drawback: it logs out the user from all devices (haven't thought how to overcome this yet). -
matrix almost 4 yearsI agree with your approach. When we talk about possibility, MQ are way more stable than we thought.
-
Valentin almost 4 yearsI finished the happy path for this idea and it seems to work fine. Micro services can be totally independent and only check against their local copy of the black list. If they are down they will receive all messages when they go up again so no risk of loosing a message. Assuming there are no glitches in the MQ. Now I am looking into the issue how to do CSRF protection, not sure how this will play out.
-
Valentin almost 4 yearsI just added the grantedAuthorities and the user id to the JWT with this information I am able to use the WebSecurityConfigurerAdapter like I would have the real user database in my micro services (antMatchers etc.). If the user roles and permissions change this needs then also trigger an invalidate message to the MQ to inform the other microservices that the current JWT token with the included rights are also invalid.
-
Meir almost 4 years@TravisTerry thanks for your implementation. My only question is I need to extract the userId from the token before its decoded (because I dont have the secret - ) to be able to query the DB and get the lastLogOut becuase I cant decode without lastLogOut. How do I decode without the secret?
-
İsmail Ceylan over 3 yearsif we are gonna access to database then we can retrieve the user's info rather than jwt version etc.
-
madllamas over 3 years@Meilech, you don't need the secret to decode the JWT, the secret is used to verify the signature not to decode it. So, you can extract the userId from the token, lookup the secret with it, then verify the token signature using the secret.
-
user2770362 over 3 yearsgood one, but apparently, would still require a DB lookup
-
Anas khan about 3 yearsThe problem is not related to client side deletion of JWT but the server side. on the client side we can simply delete the JWT token but on the server side we cant delete it as the JWT token itself is stateless . basically here the issue is about handling the corner cases where attacker might have already compromised the token so we must have a mechanism in place to revoke the specific JWT token
-
Totoro about 3 years@KoushikShomChoudhury how so? Could you please explain?
-
Koushik Shom Choudhury about 3 years@Totoro Refresh Token acts as a Debouncer/Throttler. The DB will be checked only when Refresh Token has expired or the time window has ceased, and in such a case the Refresh Token is regenerated and DB is made aware of the regeneration until the next time window. This is done because Access Tokens do not guarantee invalidations.
-
Totoro about 3 yearsWhy do we need DB to track refresh token generation. Can't we simply sign refresh token with expirytime and when expired generate new refresh token.
-
d249u7 over 2 yearsThis approach seems to be the best proposed. But, if I have multiple servers then I'd have to sync the token labels whenever there's a change, right?
-
Aman Kumar Gupta over 2 yearsThanks @Eren, Yes if you have multiple servers and there is any change in token's configuration then offcourse you need to sync it again. And there is also way to destroy the token via label by calling jwtr.destroy(jti) ("jti is json token identifier") you can pass it in payload while signing the token and if not passed then library will randomly generate the jti of token. Please refer here for more details "npmjs.com/package/jwt-redis"
-
Aman Kumar Gupta over 2 years@Eren Updated proposed answer as well. Thanks!
-
krupesh Anadkat about 2 yearsThis is the best way I think, I am going to put it in use right away. Thanks for the answer!!