Our API is developed on API Gateway + Lambda. Auth logic is laying inside every lambda function.
To handle authorization our API provided short lived access token and very long lived refresh token. The reason is why our refresh token lives so long is that we have anonymous users so they cannot re-login.
To improve security I want to make all refresh tokens possibly refresheble. To do that we had "refresh token handler" (Lambda behind APIG) with simple logic:
- mark current token as used (store this info in SQL DB)
- create new token
- return new token to a client
But there is a issue when due to network issues client is unable to save new token, but previous token is already marked as used. This issue happens because even if client closes HTTP connection then "refresh token handler" Lambda doesn’t know nothing about it and continues to work — it makes DB commit with marking current token as used.
Is there a way to handle this logic properly? There is possible workaround with Acknowledge request when new token is saved on client side, but this solution not looks like the best one.
UPD: Lambda authorizer function has the same issue as a regular lambda — even if connection is closed – lambda execution continues.
2
Answers
The same issue exists for authorization servers that use rotating refresh tokens. The server side behaviour is correct.
Reliability is best handled by clients. Any OAuth client that calls an OAuth secured API should use logic similar to this pseudocode. If a network issue occurs, the user must re-authenticate, but that will be rare, and everything remains reliable.
Note that authorization servers typically return an
invalid_grant
error code when they reject a refresh token. and you should consider something similar, to give clients what they need.CLIENT GUIDANCE
As a person providing APIs in the past I have typically handled this via client documentation and perhaps a small code sample.
There are other potential reasons why tokens can be rejected, rather than just expiry. So coding a resilient client is in the interests of any client application.
Out of interest my OAuth code samples all use this technique – here is a Node.js example.
ANONYMOUS USERS
I would question the use of tokens for anonymous users. It is a little dangerous since there is no security there, yet the API validates a token and can make false assumptions. Instead consider designing separate unsecured endpoints that can be called without credentials.
You will face this issue also every time a client has a slow network connection. What you could do it, to allow using the refresh token multiple times for a short interval.
Auth0 does this for example:
https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
So you could also define an interval of a few seconds, so that the request won’t be denied. Try different intervals to test, which one works the best in terms of user experience and also security.
An additional note regarding security:
You should not only keep track of the current refresh token, but also the previous issued refresh tokens in the chain. Because you never know if the user is legitimate to use the token. So in the case that a refresh token has been already issued and a second request is made with the old refresh token outside the reuse interval, you should invalidate both tokens.
This is also explained in the guide I shared.