I understand that having refresh tokens to generate access tokens makes your servers more scalable, since you can have a dedicated server just taking the refresh token and provide an access token.
But I'm wondering if the concept of a refresh token also provides security benefits?
In the end it doesn't matter, if either an unlimited refresh token is leaked or if you just have an unlimited access token that is leaked. In the end you have to invalidate one token, no matter which case. Am I right with that or am I missing something?
Related
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.
If we pose a question "Why not use a non-expiring access token, and not bother with a refresh token?", the answer would probably be "Because if an access token is stolen, the malicious actor has X time (the lifetime of the said non-expiring access token) to perform malicious acts on behalf of the user that token was generated for." So the way that problem is solved, as far as I understand, is by, on successful authentication, sending the user a token-pair of a short lived access token, and a longer lived refresh token. I don't see how this isn't just an attempt at circumventing the original problem. The problem apparently lies in the theoretical possibility of the access token being stolen. So that if it ever is, it's validity expires quickly, so the malicious actor can't be authenticated for a long time. In this hypothetical situation, if whoever can steal the access token, why can't they steal the refresh token instead? The usual answers I got were something along the lines of:
"You have to store the refresh token in a safe place." This makes no sense to me. Why wouldn't I store both the access token and refresh token in a "safe place"?
"The access token has a higher chance of being stolen because it's used more often than a refresh token". In this case, I suspect that "stolen" means "sniffed", as in a Man in the Middle attack. I have a few sub-questions about this one. 1. Why is this applicable? Aren't HTTPS headers/body encrypted? If HTTP is assumed in this question, why are we even talking about protecting against vulnerabilities? Which leads nicely into: 2. In practice, how does this "sniffing" of requests look like? Why wouldn't the malicious actor be able "sniff" every single request being sent, and eventually find the refresh token one?
"In a microservice environment, the access token is sent to all services, while the refresh token is sent only to the authorization service/server." This sounds like the most valid of all, but I still have a question. What difference does this make? It sounds like the authorization server is assumed to have greater security than other servers? I guess it makes sense only when taking a statistical approach, because to steal an access token, any of the X servers need to be exploited, while to steal a refresh token, only one server needs to be exploited. Although this is just my assumption, and it somehow doesn't fit in with the point of this security concept. Also, it doesn't seem like this concept was created to solve a server issue.
I guess my question is:
"If we assume that there are any inherent vulnerabilities with the concept of the access token, or with using it, or with how it's stored etc... What makes the refresh token less susceptible to these vulnerabilities?"
Whilst the security properties of both the access token and the refresh token "at rest" are the same indeed, the difference is that "in transit" a refresh token is easier to secure than an access token because of the way it is used, as explained below.
Firstly the access token is only ever sent to the Resource Server(s), the refresh token is only ever used towards a single Authorization Server. A Resource Server is considered less trusted in many scenario's (the Authorization Server is - by design - a trusted component for the Client) and as you mention, there may be a lot of them which may have different levels of security that apply to them.
Secondly, the refresh token flow towards the Authorization Server may use a "rolling refresh" of the refresh token which means that at the time of access token refresh, a new refresh token is issued as well, which invalidates the old refresh token. This is a pretty common implementation pattern for Authorization Servers.
Lastly, and perhaps a bit of a long shot, the access token is used in many more requests than the refresh token so the chances of any vulnerability that applies to the transport layer (timing attacks) are proportionally increased.
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.
We are using MSAL library and invoking the end_session_endpoint url for logout, It is not invalidating the access token.
If we use the same token after logout, it still works. Any fix for the same.
Is there any particular way of doing the signout from web applications
Note: We see this issue in mobile as well with the library react-native-ios-android-appauth-b2c
That's as per the specification. Access tokens can't be revoked or invalidated.
It's documented here.
"Clients use access tokens to access a protected resource. An access token can be used only for a specific combination of user, client, and resource. Access tokens cannot be revoked and are valid until their expiry. A malicious actor that has obtained an access token can use it for extent of its lifetime. Adjusting the lifetime of an access token is a trade-off between improving system performance and increasing the amount of time that the client retains access after the user’s account is disabled. Improved system performance is achieved by reducing the number of times a client needs to acquire a fresh access token. The default is 1 hour - after 1 hour, the client must use the refresh token to (usually silently) acquire a new refresh token and access token."
Refresh tokens can be revoked.
The access token cannot be invalidated. It's a bearer token, so it can be used until its expiry by anyone holding it.
In your case there's probably no need to invalidate the token at logout. You can simply delete it on your end, making sure it's not persisted anywhere.
The end_session_endpoint endpoint you mentioned will only clear the B2C session cookie in the browser and the user state on the B2C server, which are not directly related to the access token.
Im building a REST services for existing product. Now to authenticate these, there needs to be some mechanism. To give specifications, I have a Db which stores userid and password . I have to authenticate using these credentials.
In above should I use OAuth or JWT? I prefer to use JWT to generate token first and pass token along every request.
Also From my understanding, I understand OAuth should be used when you have multiple consumers like games/apps using Facebook login. In my case, I don't have any have multiple consumers.
Please advise
Although it is true that OAuth is an authorization framework, it does help with JWT. JWT is a token specification, meaning, how you manage and issue tokens is largely left undefined. For instance, when your token reaches it's expiration, do you want your user to be abruptly logged out? By default, if you're using tokens with a certain duration, this will happen if you're checking for expired tokens, which you should be doing.
An OAuth Authentication server can serve the purpose of issuing an Access Token in JWT, and a Refresh Token. The access token will be included in every request, and the refresh token can be used when the access token is expired or about to expire to acquire a new access token. This is useful when taking into account the potential need to revoke a users access to your application. If you set a short access token life, then you'll be able to revoke access more quickly by removing their refresh token.
The technologies are different and not directly comparable because they solve different problems and are intended for different uses.