I made a simple test application which uses a hybrid flow to authenticate .
I store the refresh token as a claim and so i'm able to refresh tokens.
But what ist the recommended best practice when to do that?
on which event should I validate the expiration? Or should I wait for an unauthorized event ? Is there any example for this?
I know I could check the expire of the token before a request ist made or I may wait for an unauthorized, but is there any recommended best pracitice way when or in what kind of event to do that?
You typically store the refresh token in some persistent data store since the whole point of it is to get long lived access to an API.
You then use the access token as long as it is valid (e.g. use it 'til you get a 401 from the APII). Then you refresh the token using the refresh token.
Related
I'm building a REST API and using AWS Cognito's user pools for authentication. I've got a "get_token" endpoint that returns the JWT access and refresh tokens to the user, which they use to authenticate access to the other REST endpoints provided by the API.
The access token has an expiration timeout. If the user of my API is an application program, what are the best practices for the application to handle when the access token expires? Does the application have to remember the username/password and re-authenticate to continue? Is using the refresh token to get a new access token and use that going forward the best approach?
Is there any documentation, suggestions anyone can point out that might help me out?
Cognito provides 3 types of tokens, id, access and refresh tokens when you login. The way this usually works is that you send either of the first two (depends on whether you want to be sending user payload information to your backend) to your backend via an Authorization header and verify the token there.
Your id and access tokens usually have a shorter expiration time compared to the refresh token. What you should do is, when the id (or access) token expire, you should use the refresh token to generate a new id (or access) token. When the refresh token expires that means that you can no longer generate new id/access tokens from it. In this case, the user (or app) must login again.
Please don't mark as duplicate I came through a lot of questions like this but still I didn't get the point of refresh token. Some of the reason they said are:
If an attacker gets the access token it will expiry soon
But where I am confused is if the attacker was able to get the access token why they wouldn't be able to get the refresh token (both of them needed to access token by JS to sent request so they needed to store in local storage)
If the attacker gets the refresh token we can block it in server.
But we can also block the access token in server right. (with DB)
Note I am not talking about OAuth refresh token, because as per the answers I read,
The idea of refresh tokens is that if an access token is compromised,
because it is short-lived, the attacker has a limited window in which
to abuse it.
Refresh tokens, if compromised, are useless because the attacker
requires the client id and secret in addition to the refresh token in
order to gain an access token.
So it makes sense here but what about JWT?
Typically the access token gets sent with every request, and to your API.
Typically a refresh token only gets sent once, immediately expires after use and only goes to your authentication server. All these measures generally reduce risk.
JWT and OAuth2 can be used together, and it's highly recommended to use OAuth2 instead of trying to write something from scratch.
I talk a bit more about the pitfalls in my article: https://evertpot.com/jwt-is-a-bad-default/
The refresh token allows the client to make a call and ask for a new access token. For setups where the access token does have a certain expiry, the refresh token will typically have an expiry which is later than the access token itself. Here is a typical workflow using access and refresh tokens:
The client authenticates to the server via 1FA or 2FA
The server responds with an access token having an expiry in 5 minutes, along with a refresh token which expires a minute later
The client then uses the access token as needed.
When authentication fails using the current access token, under the hood the client will take the refresh token and hit the server to get a new access token. We then go to step #2 above and recycle.
Note that for certain instances, the refresh token is not needed. One example would be sites like Stack Overflow, which uses token which never expire. Another example would be certain high security sites such as banking sites. In these cases, the site might force you to reauthorize via 1FA/2FA in order to keep the session going.
One way in which an update of the authentication token can be carried out through another and without exposing it to client applications (avoiding its use in a malicious way), is to store it in a cache system such as REDIS and in the When the request token has expired, check in storage if the user has a refresh token that allows him to regenerate the authentication. This could be implemented within the same middleware that validates the token that accompanies the request or in an endpoint intended for this purpose.
So, i'm trying nest js for a side project. Reading a lot lately about jwt authentication flow. Conceptually, the flow would be something like:
Client logs in and receives and access token and a refresh token. Access Token will be short lived and will be stored in memory, not in localstorage, to reduce the risks of being stolen.
Refresh token will be used only when the access token is expired to get a new one. The new one will be stored in memory. The refresh token will be stored in an httpOnly cookie, so no javascript access will be allowed hence improving the security.
Everything is cristal clear, but, my question is... why do we need the access token and why don't we always use the refresh token? In the end, if we are trusting the refresh token to generate new access tokens... why don't we simplify the whole thing and use only the long lived, stored in an httpOnly cookie on every request?
I mean I get the whole process, I just don't get why is not "secure" to use the token stored in an httpOnly cookie every time.
Can anyone share some light here?
Thanks!
You use the access token to access the API. It contains the necessary claims to authenticate and authorize the request.
The refresh token is a separate token that you use to renew the access token and you can not use the refresh token to access any API, as it is typically just a random string without any specific meaning (no claims).
The refresh token is never sent to any API and having separate tokens gives a better separation of concerns. By using refresh tokens, we can have short-lived access tokens, so if the access token is stolen, it can only be used for a short time. The refresh token is stored in a more secure way and it is only used between the client and the identity provider, so there is less risk that it will be stolen or intercepted.
Some platforms (like ASP.NET core) stores the token by default in the session cookie) but to secure it it is encrypted using strong encryption. This means that the hacker or browser can't see the actual tokens inside the cookie.
More you travel, more you exposed.
As you know the refresh token is meant to be used in case of short lived access token expiration. The idea for the use of two tokens is very simple. As access token (short lived token) will travel more frequently over the wire, increasing it chances of getting it caught by external parties. Therefore, short life expectency of access token will deny the access to the resouces for longer run in case of compromisation.
If the refresh token is secured, why don't we use just the refresh on
every request?
Nothing can make the refresh token secure. It's totally client responsibility to store it in secure location/storage for later use.
I’ve been spending hours and hours on this, this is the first time I am using JWT and would really need some of your thougts.
Right now I store my tokens in separate httpOnly cookies (my access token expires after 15 min and refresh token after 7 days).
I have read that the most secure way to store the tokens is actually using a cookie for the refresh token and in-memory (like in a variable) for the access token.
While I understand this is secure, I do not really understand how it would work in practice. Would it mean that we have to create a new access token with our refresh token on each request? Or is there a way we can make it valid and copied to new variables until it is expired?
I am using react and node btw.
I spent days reading about this too.
From what I gathered a solution would be something like this:
User logs in with login and password.
Server generates a refresh token long lived to be stored as an HttpOnly Cookie, preventing XSS attacks as it can not be accessed by Javascript.
Ideally some sort of blacklist can be used server-side to prevent re-use of refresh tokens that have not reached their expiry but have been replaced.
Generate an access token which can either be stored in localStorage or in-memory (in a variable). The access token has a short expiry life of a few minutes.
If stored in localStorage, the token will not disappear on a reload of the page/browser (F5). It will also be visible in the console/storage.
When using localStorage to check if user is authenticated, the code will try to read the token from localStorage, jwt_decode it and set a user variable with the data that is in the token.
As tokens are not encrypted, just base64, their values can be changed in the dev console. A page that is "role: admin" only will be rendered if the permission is changed. The API will be responsible to check for permissions and reject the request if the token has been tampered.
Afaik, if it is stored in a variable it is a little less visible, it also gets wiped when reloading the page/browser.
When using a variable, to avoid refreshing the access token on every request, we can use the Context API, by creating a Component with the authenticated user context that will wrap the App/Router and then on every page that needs to be protected import and use this context and redirect if needed.
When the access token is not valid anymore, because it has reached its expiry, or because it has been wiped, the API call will get rejected. Intercept this call then call the API refresh route to use the refresh token to generate a new access token.
I use axios with axios interceptor to intercept the failed request, call the refresh route, set the renewed access token, then retry the failed request. (needs to be a GET request to avoid CSRF errors apparently).
In addition (not in place of), a setTimeout can be used to automatically refresh the access token every X minutes to prevent letting it expire.
To log out, remove the cookie (eventually blacklist) and wipe the context / localStorage.
Using axios, axios.defaults.withCredentials = true; makes sure that the cookie is sent with the requests and { headers: { 'Authorization': `Bearer ${access_token}` } } makes sure the access "bearer" token is sent with the request. These can either be set as defaults for every request or per request hence these 2 syntaxes.
Github example with Flask and React
After doing some research in using JWT with Access Token and Refresh Token for authentication. I understand this in this way.
After login, return to user Access Token and Refresh Token (using same technique JWT for both).
Saving Refresh Token in Database (one User can have multiple Refresh Tokens for multiple devices).
Whenever user sends a request with invalid Access Token, check Refresh Token and call another api to get new Access Token (doing this in client side). After that, call api to get data again with new Access Token.
If Refresh Token is invalid, deleting its record in database and user must to login again to get new Refresh Token.
Does I understand Access and Refresh Token technique correctly? Please give me some advices. Thank in advance.
Of the 4 steps you listed, some look more or less correct while others do not. I will begin this answer by giving the premise for why refresh tokens were created and what is their main purpose.
Using the JWT pattern with only access tokens, there is a potential usability problem when the JWT token expires. Consider as an example a banking website. When a user logs in, he receives a JWT token with a certain expiry (typically stored under the exp key in the claims section of the token). If the token is given say a 5 minute expiry, then from a usability point of view, it means that the website would have to force the user to manually login every 5 minutes. Obviously, this is not the best user experience, because it means that a user who happens to be in the middle of some business process when the token expires might lose all that work. This is where refresh tokens step in to alleviate this problem.
Using the JWT pattern with refresh tokens means that the user receives both an access and a refresh token. A typical workflow here might be:
After login, return to user Access Token and Refresh Token (using same technique JWT for both). The receiver notes when the access token is set to expire (say 15 minutes).
As the expiry of the access token approaches (e.g. 10 minutes), the UI will send the refresh token to the backend to obtain a new access token (and refresh token). This could be done explicitly, e.g. on a website which displays a popup asking if the user wants to continue. Or it could be done in stealth mode, with a REST call being made under the hood to get the new access token.
For the edge case where the refresh token cannot be used to obtain a new access token, then the very next user action which requires authentication would fail. In this case, the user would have to redirected to the login page. But, as this case should generally be rare, it does not disqualify the refresh token pattern.
I would also point out that storing the access/refresh tokens in the database largely defeats the purpose of the JWT pattern. One major reason for using JWT is that it pushes the user session state out of the application and onto the user. By storing tokens in your database, you are totally making your user sessions very stateful, which has all sorts of potential drawbacks. Consider using the suggested workflow above to avoid doing this.
The way I see it, your refresh token needs to be stored and associated with the device and the user.
Example:
User Logs In in Device A
Call Login endpoint
Validate user is valid
If valid, generate a refresh token associated with the userid & device
id
store required data to your table or storage engine (user_sessions..etc)
user_id | device_id | refresh_token | expires_at
Return the payload with access_token, refresh_token , access_token_expires_at, refresh_token_expires_at
Front-end, store the payload
when consuming a resource, check the following
If refresh_token_expires_at > now then logs them out , show your session is timeout (or you can have a never expired refresh_token.. ex. refresh_token_expires_at can be 0)
if access_token_expires_at > now then call refresh token endpoint along with your payload.
on the refresh endpoint, validate the call and check the refresh token against the data stored.
if refresh token is valid for this user+device, generate a new access_token
return the access_token and its expires_at
If the refresh token is INvalid , return invalid
front end will log the user out.
** in any case, if a refresh token was compromised, it will be only for that particular device/user. A user can then deactivate or remove the device from their list. This action will invalidate the refresh_token on their next refresh call.