I am trying to work out if there is a maximum recommended expiry for a refresh token in the OAuth2 standard. Ideally, I would like to find concrete recommendations that take into account the nature of the secure interaction or any associated risks (eg personal data).
Background- The OAuth2 standard provides a mechanism for obtaining new access tokens using a refresh token. Access tokens are expected to have a 'short' expiry and refresh tokens a 'long' expiry.
There are many examples online that talk about access and refresh token expiry durations for different applications (example), but none of these come with particularly strong rationale or a clear justification for a particular length.
This is for a healthcare application where data security is critical. We would like to use a long refresh token length (90 days) but I haven't been able to find guidance to help me understand the risks of using such a duration.
I'm working from: https://www.rfc-editor.org/rfc/rfc6749
The question that comes to mind is why 90 days if the data sensitivity is critical? A session time such as 30 minutes seems like a better option. Is this related to poor login usability where users forget passwords? If so, OAuth can help. Some notes of mine here may help a little .. https://authguidance.com/2017/10/24/user-sessions-and-token-renewal/
Related
I've implemented lots of Restful APIs and web applications, I used to generate a JWT and give some time for expiration.
Currently I am developing mobile apps, and they all work on the same Restful APIs, but I am a bit confused of should the token expires in mobile apps and log out the user?
On many places, websites and as I do know JWT should never ever live eternally and the time for expiration must be kinda short period of time, maybe one day or less.
But if the mobile logs out the user, would it be considered bad User Experience
On the other hand, the user might click Remember me check box, so how would the JWT get expired?
Any idea would be appreciated.
There are several different ways to handle JWT expiration. First thing is to determine the value of your token. If you're using the token as a log-in to a game server, you might not be as worried about having a week-long expiration as you would for a banking app.
There are lots of ways to handle token expiration, but the most common I find below.
Automatic time-based expiration. This is a best practice, because a hijacked JWT will have less value. As you mention, logging the user out unexpectedly can be a poor experience, so one option are to include a "refresh" token, that can be exchanged once for a new, fresh, valid JWT token when the shorter-lived token expires. Refresh tokens have a longer lifetime, and may be bound to additional details such as a secure element on the device, or a policy such as in-session only (e.g. must obtain a new refresh token on app restart).
Policy-based revocation - instead of relying on a baked-in timeout, you can issue a revocation of the JWT. This relies on your services deciding when to revoke a login, and publishing the revocation somewhere it can be checked. This basically is what opaque tokens do, and thus you've just thrown away one of the advantages of JWT, but you can time out a session based on activity observed by your services.
Generally, these token management policies operate independently from the "remember me" function, which is usually a special "long-lived" (e.g. forever, 30 days, 90 days etc) token that is secured behind a secure element (e.g. fingerprint recognition, password etc) on the device that's used to obtain session tokens when a user starts a new app session.
Recently, I implemented the JWT strategy using passport and node.js... however, I am beginning to worry about the concept in general. Isn't it true that once someone has access to the JWT, it can be used to retrieve protected data? And isn't gaining access to the JWT, as easy as using chrome dev tools?
I could try and reduce the expiry date, however... isn't it true that as long as the user details are the same, the token generated will also be the same every time? So what's the point of the expiry date, if you are going to end up with the same token anyway? I am sure that I missing the point here somewhere. Guidance would be appreciated. Thanks.
Isn't it true that once someone has access to the JWT, it can be used to retrieve protected data? And isn't gaining access to the JWT, as easy as using chrome dev tools?
Generally speaking, it shouldn't be an issue if the user can access their own JWT -- because they're the one who is allowed and should have access to that token. (Which is what Dev Tools would allow you to access, but not other people's tokens.)
It becomes an issue when someone else can access that user's JWT, which is when things like using SSL/HTTPS show their value (because encryption prevents another user from sniffing traffic and retrieving the JWT, for example). This is a fairly broad topic to try and cover though, but ultimately if someone else can access some random user's JWT then there are security issues, yes. It's not strictly related, but I enjoy this Auth0 article which talks about the differences between JWTs and cookies (which you may already understand -- and hence it may useful/interesting) and some of the related security concerns and how JWTs fit in to the picture.
I could try and reduce the expiry date, however... isn't it true that as long as the user details are the same, the token generated will also be the same every time? So what's the point of the expiry date, if you are going to end up with the same token anyway?
The token's expiry is stored within the body of the token (under a exp key), hence the token's value does change whenever a new token is generated with a different expiry time. RFC7519 states the "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. The processing of the "exp" claim requires that the current date/time MUST be before the expiration date/time listed in the "exp" claim., hence if the library you're using is acting correctly in this regard, then a token with an exp value in the past won't validate correctly and hence the token is unusable.
As I understand it, the typical (and simplified) usage of JWT refresh tokens is as follows:
User logs into the system. User is granted a refresh token and a short lived (e.g: 10 minute expiry) access token. The refresh token is stored in the database of the "authentication server" for revocation purposes. Any requests made to the app ("resource server") will use the short lived access token.
When the user's 10 minutes are up, the client will send a request to the auth server for a new access token using the refresh token.
When the user changes their password or revokes access to a specific signin (in the case of theft, a lost device, etc), the refresh token is removed from the auth server database and rendered invalid.
Thus, when a user accidentally leaks his password out or loses his device, he can simply change his password, which would cause all previously issued refresh tokens to become invalidated.
However, the obvious security hole here is that the short lived access token is still perfectly valid for the next 10 minutes. And 10 minutes, no matter how short a time, is still plenty of time for a malicious user to cause some damage.
The only possible solutions I can think of are to:
maintain a blacklist or whitelist of access tokens. This makes the
usage of refresh tokens seem pretty redundant. If we're going to hit
the database on every request or to keep a cached list of blacklisted
access tokens, then what's the point of having a refresh token?
make the expiry of the access token shorter (e.g: every 1 minute
instead of every 10 minute). This doesn't solve the problem perse, it
just does some damage control, since it shortens the window of time a
malicious user has to do damage. And hitting the database for a new
access token every minute doesn't seem much better than hitting the
database on every request.
I have been working on the exact same problem. Although I cannot say I am any sort of definitive authority on the subject, I'm glad to share what I came up with based on a lot of research and building out a proof of concept.
The requirement is to have instant token access token revocation. During regular operation of the application, the actual probability of the scenario of a malicious user gaining access to someone's account is relatively low. This is not to say it should not be accounted for, but it's not going to be the case for 99.9% of request that come into your system, thus having it check the access token against the database on all the requests where it doesn't matter is bad design in my opinion.
However, bad design or not, it doesn't change the requirement. Requiring the access token to be refreshed every minute does not seem to be much better as it would put tremendous strain on the auth server and database. Managing an in memory access token revocation list wouldn't do much good because it wouldn't be shared across instances. Depending on your volume of users this may be able to get a way with using a database for while, but I don't think it would scale beyond a certain point.
The solution I chose to go with is using a shared in memory database/cache. I've evaluated Cassandra, Redis, and Apache Ignite and for the time being, decided to use Ignite. Because I am not sure how it will perform once this goes to production, I've made the components easily swappable for another in memory solution in case the performance is not sufficient.
I have a JWT filter responsible for validating each request, at the end of which I make a call to the shared cache to check a access token revocation list. I anticipate the list will be empty the vast majority of the time. To further reduce potential performance degradation, I hash to tokens to about 40 characters using MD5 before revoking them. This capability allows me to have an hour long access token life and a refresh token with an 18 hour life without worry that I won't be able to remove a malicious user if the need should arise.
Personally, I don't see a way around keeping track of some user state on the backend. The trick is to do it in such a way that you can still easily add instances of your backend to scale your application.
The purpose of JWT tokens is that they are self-contained and live on their own for a short while. If that does not suit your requirements you can revert to another type of access token, namely an opaque one that requires so-called introspection at the Authorization Server (AS). You are right that (if the results of that call are not cached) that call will hit the AS every time and partly defeat the purpose of the refresh token but on the other hand, actively having to revoke cached access token results from each Resource Server that has done an introspection call will result in a management and overhead nightmare.
There's no silver bullet. You will have to choose the access token type, expiry and cache duration that matches your situation an security requirements best.
We are planning to implement OAuth2 spec and are reviewing the "access token" implementation.
Looks like the specification gives a lot of freedom to implementors and we are looking
for some best practices:
What to put in the access token? We want to strike the good balance between size and usefulness.
I realize this is very application specific but perhaps there are some things that are really worth having.
So far we identified the following fields:
User Identifier
Expiration date
Version (so that we can change the format in future)
Client Identifier (i.e. app who requested the token)
Some additional attributes (e.g. password hash) would be stored in the database and looked-up during
authentication (using the fields in the token as a 'key').
How to secure it?
We are leaning towards securely signing the access token (HMAC) so that we know if it was tampered with.
The fields in the token would be then readable by everyone.
The alternative is to encrypt (AES) the whole thing and make it completely opaque to the user. This makes
it much bigger (in terms of bytes). It looks like FB is now using encrypted tokens (http://developers.facebook.com/blog/post/572/)
Any suggestions as to industry best practices?
Thanks,
Piotr
As long as you can map the access token you issued back to a user in your backend along with expiry date etc, then it really doesn't matter how it's generated (other than it should not be predicable). The spec doesn't dicate the implementation detail.
The token can be a uniquely generated string mapped to user state in the backend, or you could encrypt user info and expiry dates etc into the token itself, in which case consider SWT. The SWT format defines exactly what you describe. It contains information in clear text about the user, clientId, scope etc, but then also provides an encrypted key to make it tamper proof. With a shared secret it's posible to validate the key even if it's generated on another server, or by another party. They tend to get pretty big so not ideal for passing in the query string.
There are cloud based STS solutions which can generate tokens for you. Azure ACS for example can generate SWT tokens via an OAuth2 endpoint and manage all of the state relating to refresh tokens, expiry dates, and authorisation grants for you. What you save in effort in using this, you'll probably loose in figuring out how to integrate with it, but it's quite neat.
I'm using GData's AuthSub so that my administrative application doesn't need to store user/password information. I just came to the point in the documentation where I learned how to exchange the first, single-use token, for a session token (http://code.google.com/apis/accounts/docs/AuthSub.html#AuthSubSessionToken). And then this statement jumped out at me:
You can ignore the expiration date, which is not currently used; session tokens effectively do not expire.
Would someone care to explain how a non-expiring token is not a security issue? What does "effectively not expire" really mean? Theoretically if a malicious application manages to obtain one of these tokens, can it continue to use it regardless of password changes? Is it possible to see what session tokens have currently been issued on a Google account?
In short, my paranoia has taken hold, and I need a big smart person to comfort me!
EDIT: You can manually revoke tokens at https://www.google.com/accounts/IssuedAuthSubTokens
Yes, in fact if a session token never expires it is a vulnerability is recognized by CWE-384 , If the session takes a really long time to expire then it is a violation of CWE-613. Both CWE pages give a great explanation of the vulnerability. I do not know the specifics to this applications, but normally a Session token can be used to immediately authenticate without need for the username/password.