Why refresh tokens instead of long lived access tokens? - security

What's the point of refresh tokens without Refresh Token Rotation?
I've read a few articles on the matter, such as https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/#What-Is-a-Refresh-Token- and https://auth0.com/blog/achieving-a-seamless-user-experience-with-refresh-token-inactivity-lifetimes/.
As I see it, anywhere the client could store a refresh token, it could also store a long lived access token, so it can be attacked in the same way, and since the refresh token issues infinite access tokens (without rotation), it essentially holds the same power as a long lived access token.
Also, the same conditions and operations for invalidating a refresh token could be applied to invalidating access tokens.
With Refresh Token Rotation, I see the point, it greatly reduces the surface.
Is it the point of it without RTR as well? Reducing the surface of attack, since access tokens are sent with every request, whereas refresh tokens are only sent once every [access_token_expiration_time] ?

Related

What is the purpose of the refresh token if it can be stolen as well?

Main purpose is security: Shortened access token is important, because if someone stoles an expired token, then the attacker cannot use it, because it is expired.
We can obtain new access token with refresh token without the client needs to login again. Refresh tokens live longer.
I still don't get why refresh tokens was invented, because it can be stolen the same way as access token, right? If someone stoles refresh token, then the attacker gets access token as well.
Refresh tokens are being sent on the network way less than access tokens, so if your network is being sniffed, they will find the refresh token every 30mins (for example) in one request, so the window for you to be exposed is very small (you need to be sniffing in the right moment and for a long time)
Refresh tokens can be revoked, so if a user's token is stolen, the user can revoke its refresh token, but with a stateless access token with a long expiration time, it's not possible to close a session
If you want to store your access tokens, so they are revokable and get rid of refresh tokens, then you are not using a stateless JWT token, so you have to hit your database for each request you receive to check if the token is still valid or not.

How do I implement Refresh Token Rotation?

If I understood the refresh token rotation right, it means that every time we request a new access token, we also get a new refresh token. If a refresh token is used more than once - we invalidate all the refresh tokens that a certain user previously used, and a user has to go through the authentication process again.
Does it mean that we need to store all the refresh tokens (all the old ones) in a database?
Can't we simply store the last refresh token, only one (that wasn't used yet), and with each request to get a new access token we would check if the refresh token sent in the request is in the database, and if so, we would create a new access and refresh token and overwrite the old refresh token in the database, so that old refresh tokens can't be used to get new tokens?
How long should such refresh tokens live?
Yes, but all will usually mean "all in a given time frame". The time frame will depend on your needs - for how long do you want to be able to identify any potential refresh token leaks.
You can, but then you don't get any better security than without using token rotation. This is because you never know who used the current token first - the legitimate user, or the malicious one, who stole your token. If it was the latter, then she will now have access to working access/refresh token pairs. The legitimate user will be left with an invalid token.
This depends on your requirements, features, security etc. You will usually find information that a refresh token should be valid for a couple of hours (usually up to 8), but I've setups with refresh tokens valid for days or even months.

Access/Refresh token confusion

I've been doing a lot of reading on this subject and I can see that there are many different opinions and approaches to authenticating using JWT.
My understanding is as follows:
In its simplest form, a JWT authentication mechanism should:
Verify username and password.
Create a signed JWT access token containing information (depending on the app's needs) on the user.
Send that token in the response.
The client then stores the token (which from my understanding there is some debate whether a secure cookie or localStorage is more secure), and sends it with each request's headers.
The server can then authorize the user using middleware verifying the JWT. No state, all information in contained within the JWT.
Assuming the JWT has no expiration (or perhaps a very long expiration date, maybe a couple of months), it sounds good because I can provide the user a persistent logged in state for a long time. The concern is, to my understanding, if the JWT was to be stolen, it is essentially an unlimited access card and a huge security breach.
So that's where the refresh token enters, the server issues both refresh and access tokens (refresh token with a long/unlimited expiration and the access token short).
The server database holds some kind of table of valid refresh tokens (so that if one is stolen it can be invalidated easily) and when issuing a new access token, validates the refresh token.
This also adds the need to add some sort of countdown mechanism on the front end where a refresh request is to be sent to the server prior to the access token expiration date so that the user won't be logged out.
And my question:
Why? If we go through all the trouble of creating a db table for refresh tokens, why not just make a table of valid access tokens and invalidate them if needed? How is that less secure than using refresh tokens?
Thank you
Access tokens aren't primarily used to provide extra security, but to provide efficiency and decoupling.
An access token can have a very short lifetime - maybe even less than a minute - but be used to authenticate multiple requests to different services within that time. Those services don't need to have any access to the authentication database, because they can trust the access token until its expiry date; that makes them faster and simpler.
For instance, if you're using a dynamic page with lots of AJAX requests, that might run in very quick succession. Those AJAX calls might be implemented as serverless functions (e.g. AWS Lambda), or as standalone scripts in different programming languages on different servers, or you might just want to make them as efficient as possible, and avoid any database access. The only information that needs to be shared between them is a public key to verify the signature on the JWTs they receive.
From a security a point of view, this is a trade-off: on the one hand, an access token for a user whose access has been revoked can still be used until it expires; on the other hand, the long-lived refresh token is transmitted much less than a traditional session token, so there are fewer chances for it to be intercepted.
To address your concrete concern:
This also adds the need to add some sort of countdown mechanism on the front end where a refresh request is to be sent to the server prior to the access token expiration date so that the user won't be logged out.
No "countdown" is needed. The code that has access to both tokens simply looks at its current access token before using it; if it has expired, or is about to expire, it requests a new one using the refresh token. It then gets a new access token, and probably a renewed refresh token - the expiry date on the refresh token represents how long the user can be idle before they are automatically logged out.
We don't need to make a table of access tokens and it is dangerous to secure.
We have to save only refresh token and add one field for valid/invalid in the table. And send access token and refresh token to the client side.
The clients send access token with each request's headers.
The server can authorize the user using middleware verifying the JWT.
After some time, the access token will be expired(access token's expired time is shorter than the refresh token's expired time).
The client sends refresh token to server.
Then the client will get new access token using refresh token(refresh token should be recreated, in other words, we can use only one-time refresh token, we have to update table of refresh token with new refresh token).
The client can get new access token and refresh token.
I hope it will be help you.

jwt access token and refresh token flow

here is my auth's flow:
The user receives two tokens (access token with expiration time and refresh token without expiration time) after logging in
for each user , The refresh token is stored in the database in a json column called refreshTokens(which is an array).
on the client side, Both access token and refresh token are stored on the local storage.
when user needs to be verified, If the access token is expired, a new access token is created using the refresh token and sent back to the user and keeps the user logged in.
When the user logs out, the refresh token stored in the database (in the refreshTokens list) is removed.
my questions are:
is this flow, secure?
do i need to save refresh token on the cookie or is local storage good enough?
That flow is according to how OAuth works and how tokens can be stored in a secure way, so "yes" to both questions. The part that is missing is how the tokens are obtained in the first place: for that the Authorization Code grant type using PCKE is the preferred way, over the legacy Implicit grant type.
An important part of this flow being secured is that in point 4 you use the list of refresh tokens kept in the database to verify that the RT was not revoked. Other than that it looks ok. You can add more security by adding expiration times to refresh tokens. Then, even if the user doesn't actively log out (you don't clear RTs from the DB), the RT will not be usable after some time.
Keeping the tokens in local storage is good enough in my opinion.
Few stuffs that popped up in my mind while reading this :
Refresh Token also needs expiration time. In fact, I consider refresh tokens as a double edge sword. Imagine a scenario where a person gets access to the refresh token, not only he gets access to the resources, he will practically gain more time with the resources. I prefer to re-generate refresh token along with access token when refresh token is being used to re-generate the access token. And, also set an expiry to it.
It is cool to store the refresh token in database. However. I do have an alternative though, you can easily use RSA algorithm and then do token generation using private key and verify using public key. This is yo mitigate the scenario of needing to store the refresh tokens.
On client side, local storage is a BIG NO from my side. What I prefer is that you use HttpOnly Cookies and set flag as true. HttpOnly Cookies are not rendered in JS and is sent to server securely as per Http protocol. This is fix the chances of compromising tokens.
Your rest concept of it is good enough.

Invalidate JWT Token in NodeJS

I followed this tutorial for using JWT token. The token expiry is set to only 5 minutes, but what if I wanted to invalidate the token after 1 minute of use? I want to be able to make an API call to /api/logout and that should delete my token.
I'm using Express and Node.
It seems like from what I could gather to do my option is to have a token db that stores the token. When I want to expire my token, I then expire/remove the token from the DB.
I've also seen people casually say "remove" the token from the physical hard space, but I cannot figure out where the token is physically stored for me to remove it.
The general benefit of a JWT token authentication is that the tokens can contain all the session information you would normally keep in your session store. This saves considerable resources, especially in request-to-response times, because you do not have to look up session data on each and every request - the client gives you all that.
However, it comes at the cost of not being able to revoke a JWT token at a time of your choosing, because you lost track of state.
The obvious solution of keeping a list of invalidated tokens somewhere in your database kind of removes the above-described benefit because you again have to consult the database on every request.
A better option would be to issue short-lived JWT tokens, i.e. tokens valid only one minute. For a web application, an average user may perform several requests in a minute (a user navigating around your app). You can give each user a JWT token that will last a minute and when a request with expired token arrives, you simply issue them a new one.
Update: Issuing a new access token after presenting an expired token is a very bad idea - you should treat an expired token as invalid, as if it has been forged. Better approach is to have the client present a refresh token which will prove the user's identity, and only then issue new access token. Note that verifying a refresh token must be a stateful operation, ie. you must have a list of all valid refresh tokens per user somewhere in your database, because if the refresh token is compromised, the user must have a means of invalidating that token.
1) Simply remove the token from the client
2) Create a token blacklist
3) Just keep token expiry times short and rotate them often
Please have a look at Invalidating JSON Web Tokens
Invalidating JSON Web Tokens

Resources