Refresh tokens should be given more care than they currently are. Specifically their scope and retention policies leave far too much to be desired.
Retention and Management
Seemingly inconsistent token retrieval
Not listed on the documentation provided (Refresh Tokens) is that the nuance around retrieving the access token from the google social provider.
Upon further review of google documentation as well as external form, I found that this flow is expected & consistent, though not desired:
This value instructs the Google authorization server to return a refresh token and an access token the first time that your application exchanges an authorization code for tokens.
Note the wording of “first time” in the above is not captured on the auth0 documentation. This wording causes the following headaches for IDP integrators:
- Currently authorized users will NEVER have a refresh_token
- Newly authorized users will only have refresh_token until a subsequent user-initiated login
- API integrators must store the
refresh_token
locally for each account, significantly reducing the ease of implementation (notably for applications which don’t need store the user for any other reason such as consumer microservice with discrete business logic).
Mitigation
- Please include a note that the
refresh_token
can be forcibly regenerated by including theapproval_prompt=force
query parameters into the/authorize
flow. - Please create an enhancement within your system to capture and retain the
refresh_token
when a response is returned from google without therefresh_token
Risks
Single service; universal take-over
In even a medium size environment (e.g. 30 services), under the current model present by auth0 it would take one application one vulnerability to globally and perpetually compromise the users of all socially (where the social provider supports refresh) authenticated users. Users would be unprotected until all access_tokens are refreshed or until they have revoked permission from the application. There is not natural expiration of the token.
In my experience, companies stop updating functionality around service 10 and stop reviewing logs around service roll out 15. This implicit trust (human nature) can cause these services to be excellent attack points.
Mitigation
There should at the very least be a panic button on the appropriate social page saying “Revoke all access tokens” to automatically revoke all access tokens (revoking an access token does also revoke the refresh_token):
If the token is an access token and it has a corresponding refresh token, the refresh token will also be revoked.
This would allow an administrator of my application to automatically ensure that my users are secure against future attacks while vulnerabilities are addressed
Conclusion
To be blunt, I feel that the service you’re offering is limited at this point. The issues above are clearly the result of expecting that the integrators to auth0 are not lazy and don’t make mistakes. I prefer to work with the opposite assumption. I’m extremely lazy and I assume everyone else is too. I make mistakes, and I know you do too.
In my opinion a better way for me to consume your services is to not expose the refresh_token
to me. But rather to expose a mechanism for me to securely refresh the access token of a user or a collection of users which performs whatever vendor specific logic in the background. Preferably the non-batching version of this endpoint would return the token json object for immediate consumption, but even if it has to be reacquired that is fine. Yes, there should be an option for the services to receive the refresh_token
but I don’t believe this should be exposed via the default read:user_idp_tokens
permission required to make a one-off request to a social provider’s services.
I want the authorization data provided to my application to have a guaranteed expiration date, such that I can shut down my application/regenerate a key and move on know that a hiccup in over-logging, over storing, under-securing, will be resolved in 2 hours. Yes, in infosec terms 2 hours is 1:59:59 too long but it’s far better than the perpetual trust that is currently expected of every single offline integration built for your system today.
Thank you for your time.