Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practices to invalidate JWT while changing passwords and logout in node.js? [closed]

I would like to know the best practices to invalidate JWT without hitting db while changing password/logout.

I have the idea below to handle above 2 cases by hitting the user database.

1.Incase of password changes, I check for password(hashed) stored in the user db.

2.Incase of logout, I save last-logout time in user db, hence by comparing the token created time and logout time, I can able to invalidate this case.

But these 2 cases comes at the cost of hitting user db everytime when the user hits the api. Any best practise is appreciated.

UPDATE: I dont think we can able to invalidate JWT without hitting db. So I came up with a solution. I have posted my answer, if you have any concern, you are welcome.

like image 270
Gopinath Shiva Avatar asked Feb 27 '15 07:02

Gopinath Shiva


People also ask

Should JWT tokens be invalidated on the server after logout?

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.

Can you invalidate JWT token?

There are several reason to invalidate a JWT token before its expiration time: account deleted/blocked/suspended, password or permissions changed, user logged out by admin. JWT is self-contained, signed and stored outside of the server context, so revoking a token is not a simple action.


2 Answers

When No Refresh token is used:

1.While changing password: when the user changes his password, note the change password time in the user db, so when the change password time is greater than the token creation time, then token is not valid. Hence the remaining session will get logged out soon.

2.When User logs out: When the user logs out, save the token in a seperate DB (say: InvalidTokenDB and remove the token from Db when token expires). Hence user logs out from the respective device, his sessions in other device left undisturbed.

Hence while invalidating a JWT, I follow the below steps:

  1. Check whether the token is valid or not.
  2. If valid, check it is present in invalidTokenDB (a database where logged out tokens are stored till their expiry time).
  3. If its not present, then check the token created time and changed password time in user db.
  4. If changed password time < token created time, then token is valid.

Concern with the above method:

  1. For each api request, I need to follow all the above steps, which might affect performance.

When Refresh token is used: with expiry of access token as 1 day, refresh token as lifetime validity

1. While changing password: When the user changes his password, change the refresh token of the user. Hence the remaining session will get logged out soon.

2. When User logs out: When the user logs out, save the token in a seperate DB (say: InvalidTokenDB and remove the token from Db when token expires). Hence user logs out from the respective device, his sessions in other device left undisturbed.

Hence while invalidating a JWT, I follow the below steps:

  1. check whether the token is valid or not
  2. If valid, check whether the token is present in InvalidTokenDB.
  3. If not present, check the refresh token with the refresh token in userDB.
  4. If equals, then its a valid token

Concern with the above method:

  1. For each api request, I need to follow all the above steps, which might affect performance.
  2. How do I invalidate the refresh token, as refresh token has no validity, if its used by hacker, still the authentication is valid one, request will be success always.

Note: Although Hanz suggested a way to secure refresh token in Using Refesh Token in Token-based Authentication is secured? , I couldn't able to understand what he is saying. Any help is appreciated.

So If anyone have nice suggestion, your comments are welcome.

UPDATE: I am adding the answer incase your app needs no refresh token with lifetime expiry. This answer was given by Sudhanshu (https://stackoverflow.com/users/4062630/sudhanshu-gaur). Thanks Sudhanshu. So I believe this is the best way to do this,

When No Refresh token needed and no expiry of access tokens:

when user login, create a login token in his user database with no expiry time.

Hence while invalidating a JWT, follow the below steps,

  1. retrieve the user info and Check whether the token is in his User database. If so allow.
  2. When user logs out, remove only this token from his user database.
  3. When user changes his password, remove all tokens from his user database and ask him to login again.

So with this approach, you don't need to store neither logout tokens in database until their expiry nor storing token creation time while changing password which was needed in the above cases. However I believe this approach only valids if your app has requirements with no refresh token needed and no expiry of the tokens.

If anyone has concern with this approach, please let me know. Your comments are welcome :)

like image 190
Gopinath Shiva Avatar answered Sep 28 '22 22:09

Gopinath Shiva


There is no way I know of to arbitrarily invalidate a token without involving a database one way or another.

Be careful with Approach 2 if your service can be accessed on several devices. Consider the following scenario...

  • User signs in with iPad, Token 1 issued and stored.
  • User signs in on website. Token 2 issued. User logs out.
  • User tries to use iPad, Token 1 was issued before user logged out from website, Token 1 now considered invalid.

You might want to look at the idea of refresh tokens although these require database storage too.

Also see here for a good SO discussion regarding a similar problem, particular IanB's solution which would save some db calls.

Proposed solution Personally, this is how I'd approach it...user authenticates, issued with access token with a short expiry (say 15 mins) and a refresh token valid either for a much longer period or indefinitely. Store a record of this refresh token in a db.

Whenever the user is 'active', issue a new auth token each time (valid for 15 mins each time). If the user is not active for over 15 minutes and then makes a request (so uses an expired jwt), check the validity of the refresh token. If it's valid (including db check) then issue a new auth token.

If a user 'logs out' either on a device or through a website then destroy both access refresh tokens client side and importantly revoke the validity of the refresh token used. If a user changes their password on any device, then revoke all their refresh tokens forcing them to log in again as soon as their access token expires. This does leave a 'window of uncertainty' but that's unavoidable without hitting a db every time.

Using this approach also opens up the possibility of users being able to 'revoke' access to specific devices if required as seen with many major web apps.

like image 25
DevFox Avatar answered Sep 28 '22 23:09

DevFox