Refreshing the Refresh Token - authentication

The way I understand Access Token and Refresh tokens is as follows:
Authenticate to App
Receive (short lived) access token and (longer living) refresh token
requests resources from App with access token
If Access token expired request new Access Token with Refresh Token.
Refresh Token expires user must reauthenticate.
Lets imagine refresh token is valid for 30 days. On day 30 the user is in the middle of some business and his refresh token expires. Does he get automatically logged out? I haven't seen that happen...
So What is refreshing the refresh token without the user manually inputting credentials?

Every time the application asks for a new Access Token (step 4 in your list), it can also be given a new Refresh Token, with an even later expiry.
Effectively, the life time of the Refresh Token is the maximum idle time of the user's session.

Related

If you implement refresh token rotation, isn't better to keep track of current user token than blacklisting used ones?

I don't see a point in which you would with implemented refresh token rotation blacklisted tokens instead of keeping track of current ones.
If you are blacklisting tokens, you would get a lot of tokens blacklisted very fast. Let's assume your access token TTL is 5 minutes and your refresh is 7 days. If user is using your app for and hour, he would blacklist 12 tokens in that time. If you have great number of users, that would be a lot of blacklisted tokens.
Problem with that is also theft of refresh token. If someone managed to steal it, they can immediately exchange it for pair of new tokens, users active token (that is stolen) would be blacklisted and thief could just use your app normally from that point. How to solve that? Your user would provide blacklisted token on next request and would be logged out, he will log in again and start normally using app but so does the thief, since his token is valid, unless you invalidate his token somehow, but for that you need to keep track of current tokens.
Why just don't keep track of current client token? On every refresh request, you just check if provided token is current users token, if it is not put token value in database to "null". That why users will be forced to log in even if they stole your refresh token since current token must be valid to even check the database if it is same as current (because if refresh token is invalid or expired, you must logout user). Next time they log in, you would set new current refresh token in database and thief can't do nothing with stolen token.
Isn't this breaking stateless rule? It does, but in classic session you need to check database on every request, in this system you would check only when access token expires.
Plus, you don't need to keep track of possible of millions blacklisted tokens and you prevent from refresh token theft.
Only downside I see is that if someone actually steals your refresh token, and you never make any requests after that, they will be logged in until they log out or somebody sends bad request to refresh token endpoint that will "lock" your account.

How to manage multi-device simultaneous login with JWT tokens?

My query is regarding supporting multi-device login for the same user at the same time using JWT tokens. I am using NestJS as my backend.
User table: userid, username, password(contains hashed password), name, refreshToken(contains hashed refresh token)
When the user does a /api/login call, on having a valid username and password, the access token and refresh token are generated using jwt passport library. The refresh token is hashed and stored in the refresh column of the user table for that particular user and the access token and the refresh token are sent to the client through the response.
During the /api/refresh call, the refresh token sent by the user is validated with the hashed refresh token that is present in the user table for that user and then, a new access token and a new refresh token are generated. The new refresh token is hashed and updated in the user table refreshToken column for that same user row.
This flow works perfectly for a user logged in with a single device. When the same user gets logged in using multiple devices at the same time, during login, the refresh token is updated in the refreshToken column of the user table for the same user row, which makes us lose an existing/valid refresh token for the same user.
Flow:
user 1 logs in using device 1 --> refreshToken column for user 1 is updated with a new refresh token
user 1 logs in using device 2 --> refreshToken column for user 1 is overwritten with a new refresh token and we lose the refresh token that was created for device 1
I would like to know what would be the best industrial practice to manage the JWT refresh flow for a user logged in with multiple devices at the same time?
The simplest way would be to keep the refresh tokens in a separate table. Usually, refresh tokens are kept separately from the user's account data, as the user can have more refresh tokens active at any given time. Whenever a refresh token is used you can find the concrete token and create a new one in its place.
By the way, there is no need to hash the refresh tokens kept in your database. They are unique to your system, they're not passwords.

Revoking JWT with No Expiration

I'm looking to employ token-based authentication for a mobile app that keeps the user logged in as long as they have not logged out. My approach is to create a JWT refresh token when the user logs in/signs up; This token never expires, and continues to refresh 20 minute access tokens.
The problem arises when they log out. I've read the best way to go about this is to blacklist the JWT on Redis to store revoked keys. However, since the JWT never expires, the record can never be removed from Redis and can start to chunk a lot of my memory.
Should I be worried about this, or is Redis memory-efficient on this respect? Is there a better way to revoke JWT with no expiration?
A JWT token is a self contained token. That means that it lives on its own until it expires and can't be revoked. So by definition it must expire. Because when it falls into the wrong hands, it'll give access to your resources without being able to revoke it. So yes, you should be worried with this implementation.
The problem here is that you trust the refresh token itself, because it's a JWT. You should in fact trust the server. Not because the JWT can't be trusted, but because the refresh token doesn't have to be a JWT.
Save refresh tokens in memory including the expiration time. You can remove expired tokens from memory. This means that only tokens that exist in memory can be used to request a new access token. And to be on the safe side, use one-time only refresh tokens.
The flow would be something like this:
the user logs in, receives a JWT access token (5 minutes) and the refresh token 1 code (48 hours). Refresh token 1 is saved on the server.
five minutes later: the access token expires
a new access token is requested using refresh token 1.
user receives a new access token (5 minutes) AND the refresh token 2 code (48 hours). Token 1 is removed from memory and token 2 is added to memory.
and this goes on for several hours.
For two days the user doesn't use the app
50 hours later: because both tokens are expired, the user has to login again. Resetting the flow.
On logout remove the refresh token from memory. And if in the meantime you wish to revoke access. Simply remove the refresh token from memory. Within 5 minutes the user has to login again.
JWT also needs to be revoked as best practice.
Yes, JWTs are self tokens and expirations already part of themselves.
But if user logs out and still their JWTs are not expired means someone can use that token to call different APIs. So it is a security breach.
To avoid such things we should maintain JTI claim of that JWT in our backend with the same TTL with the value of JWT "exp".
When the user logs out we have to clear those JTIs and notifcy the API callers about this just putting into some event service from their API Gateways should get to be notified and clear their side cached tokens if anything and cross check with identity system (Introspection).
This is we have to design the system to avoid further security related issues.

JWT token refresh (sliding sessions) and signout

I am very new to JWT and I ended up inheriting a codebase which makes use of JWT. Now there are some very fundamental problems which I am facing and I am not finding any answers. This question is not code based so please bear with me.
Let us say that my JWT token is valid for 4 hours. Here are my requirements/constraints
If a user is working at 3 hours 59 minutes. their session should get extended by 2 hours and they should not be required to re-enter credentials.
The client side java script must not cache the user credentials in any way.
It is OK to refresh the JWT token with a new one... but you must not do it on every request you make on the server. So the client has to be intelligent to refresh the JWT token when the time is right. You must not try to issue a new token on each and every request you make to the app, because we will end up in a scenario where we have 1000s of active tokens generated within the course of a session and all of them are active. this makes the signout requirement even harder.
Once a user clicks signout. the JWT token should not be usable anymore. Even though its life time is still valid.
If a signout occurs. All tokens which were issued (as part of session extension) should get invalidated. Not just the last one.
I am starting to read about JWT but it seems like my requirements cannot be met with JWT. these requirements are very easy to meet with the session id approach. but I don't want to give up on JWT just yet.
JWT life extension
You can issue a JWT with the old one. Your client app have to request a new JWT when it is close to expiration time. Client knows the expiration time reading the exp claim and can invoke a refresh service to get a new token. If the client app is closed then the JWT will expire and it will be necessary for the user to present the credentials again
Logout
It is recommended to let tokens expire, but you can use a blacklist to store JWT that are still valid but can not be used for authentication:
When user clicks logout
After refreshing a ticket close to expiration time
You will need to add to JWT an unique identifier jti. The blacklist will contain jti and exp. Once current time > exp the entry can be discarded.
See Invalidating client side JWT session

Can LinkedIn's access token renewal flow be performed on the server?

In the Facebook's Graph API, once we have initially authenticated the user, we can interact directly with the API (from the server) to obtain a long-lived page access token. This long-lived page access token never expires. (https://developers.facebook.com/docs/facebook-login/access-tokens/)
In reading LinkedIn's documentation, it appears that it is impossible to obtain an access token with an indefinite (non-expiring) access token. It seems that they expire every 60 days. However, these access tokens can be refreshed before the 60 days is up.
What isn't entirely clear from the documentation is whether or not the access token renewal can be performed on the server alone without the client's interaction. The language of the documentation suggests that the interaction of the client (browser) is required, but nothing is explicitly stated.
So, my question is, is it possible to renew a LinkedIn access token using the server alone, without the interaction of the client (browser)?
Relevant LinkedIn reference material: https://developer.linkedin.com/documents/handling-errors-invalid-tokens
As it turns out, the access tokens of linkedin can not be refreshed without having linkedin user logging in to linkedin. Please refer to the first comment here by LinkedIn employee which clearly states a note that "this refresh will only work if the user is still logged into LinkedIn (authenticated) and the current access token isn't expired. Otherwise, the user will be presented with the login dialog again."
I guess that is now a major issue for those who were previously storing the linkedin access tokens to database for later use.
I am mentioning few links here which refer to the issue with refreshing linkedin oauth2 tokens (hope this makes it clear for everyone who is struggling with the same issue):
1) This refresh will only work if the user is still logged into LinkedIn (authenticated) and the
current access token isn't expired. Otherwise, the user will be presented with the login
dialog again.
2) There is no way to refresh the token using the old authentication token/secret. User
needs to log into linkedin in order for you to refresh the tokens. We use this flow as it
protects our members and their data in the best possible manner.
3) Refreshing an access token is very simple and can happen without an authorization
dialog appearing for the user. In other words, it's a seamless process that doesn't affect
your application's user experience. Simply have your application go through the
authorization flow in order to fetch a new access token with an additional 60 day life span. When the following conditions exist:
-User is still logged into Linkedin.com
-The current access token isn't expired (within the 60 life span)
We will automatically redirect the user back to your redirect_uri without requiring them to reauthorize your application. If they don't exist, we'll prompt them to login and then redirect
them.
4) We have also standardized the duration of the authorization tokens. Previously, members
could choose to grant tokens that were as short as one day or as long as forever. Now all
tokens are 60 days in length, with the ability for you to extend them in a series of rolling 60 day increments whenever the member comes back to your application. To prevent a bad user experience in your application, be sure to proactively refresh tokens and elegantly route any expired tokens through a refresh flow.
5) As long as the user is logged into LinkedIn and their current access token hasn't expired, you can fetch an access token with a 60 day lifespan the next time the user comes to your application.
I had the same question and the LinkedIn docs and forum posts are confusing, but I'm pretty sure now that it's not possible to do it programmatically without user intervention (i.e. the user needs to login to your app via LinkedIn auth to refresh the token).