I currently work on an legacy app which somewhat loosely implements an OAuth2 flow. In short, when the user logs in with username/password, he receives an access/refresh token pair. The access token expires after 20 minutes whereas the refresh token has a lifetime of 180 days.
Now when the client gets a HTTP 401 Unauthorized due to an expired access token, it will use the refresh token to obtain a new access/refresh token pair. At the same time, we invalidate the old token pair in our backends database (we simply delete the entry).
This has some major issues since our clients are mobile apps and it sometimes can happen that a response from our server is not received by the client. So after our backend saves the new token pair, which the client doesn't receive due to for example network problems, the client no longer can get a new token pair because he still only knows about the old - now invalid - refresh token.
I was wondering if what we are doing is correct or whether we actually should never remove old refresh tokens from the DB as long as they are not expired. Or should we for example remember the last 1 or 2 refresh tokens for a user so even if a new one was created, if the client doesn't receive the response from our server, he can still try one or two times again with the old refresh token.
Or should we simply never send out new refresh tokens when obtaining a new access token and always use the same refresh token?
Is there any best practice to follow or is this all personal taste? I mean we can't be the first ones to run into this issue of mobile clients loosing responses due to network issues, right? :)
MEASURING MOBILE CONNECTIVITY OCCURRENCES
When there are mobile connectivity problems, I would expect the refresh token grant request
to fail. For the request to succeed and the response
to fail to reach the client (in such a small time window, eg 200ms) feels very much like an edge case.
I would aim to ensure good production logging around what is happening server side, so that you can be clearer about exact causes. It is easy to jump to the wrong conclusions otherwise.
ROTATING REFRESH TOKENS
The preferred behaviour from a security viewpoint is to revoke all tokens for the user when an old one is reused. However, the OIDC Specs indicate that this can cause usability problems in some setups, in which case other measures
may be appropriate.
Exact behavior is provider specific - some Authorization Servers store and flag old refresh tokens and may allow them to be reused for a time period configured against the client application.
SECURITY v USABILITY
If dealing with high worth data I would use the more secure option, but if mobile consumption data is not especially sensitive, using non-rotating refresh tokens might be an appropriate measure.
RELIABLE APPS
In some cases OAuth clients will get a 401 when using a refresh token, and in addition to the case you mention, there are other possible causes:
Apps should always be coded reliably to deal with this, eg:
invalid_grant
value in the error
response field, the user must re-authenticateNote that re-authentication is sometimes a single sign on event. To see how this looks, you can run my Demo Single Page App and click Expire Refresh Token
, then Reload Data
.
SUMMARY
You cannot always guarantee no re-logins for 180 days in a distributed systems world. In terms of next steps, my preference would be to properly identify the cause and frequency of failures, and to see if reliability could be improved in the client application's code.