Hi everyone,
we received a penetration test finding related to our logout implementation using the Auth0 SPA SDK with Refresh Token Rotation enabled.
The issue described by the testers is the following:
During logout, the previously used refresh token is rotated as expected. However, the rotation process also returns a new valid refresh token. This new token can still be used to obtain new access and refresh tokens. From the tester’s perspective, this means the session is not fully terminated on logout, because a valid refresh token may still exist and could theoretically be used if an attacker intercepted the logout response.
We followed this recommended approach:
https://github.com/auth0/auth0-spa-js/issues/1320#issuecomment-3659128853
Our question is: how should we properly address or mitigate this finding?
Is there an Auth0-recommended argument we can provide to the pentesters to clarify the expected behavior? Is there any way to revoke or invalidate the newly issued refresh token immediately during logout? Or is this a known limitation/trade-off when using Refresh Token Rotation with Auth0?
Thanks a lot for your help.
Best regards,
Moritz
"@auth0/auth0-angular": "^2.3.0",
Hi @moritz.meinhardt
Welcome back to the Auth0 Community!
Just to clarify, does the response from one of our engineers on the linked Github issue is not sufficient regarding the matter or are you looking for further clarification?
Their reply was:
We’ve previously addressed this in #1013. While I understand the workaround may not satisfy all security requirements, our current recommendation remains:
Before calling logout(), call getTokenSilently({ ignoreCache: true }). When combined with Auth0’s rotating refresh tokens, this invalidates the previous refresh token, ensuring it cannot be reused.
Why we haven’t implemented automatic revocation:
- Multiple tokens complexity: This SDK supports multiple audiences and scopes, potentially caching multiple refresh tokens. Automatically revoking all of them could have unintended consequences.
- Network dependency: Automatic revocation would make logout dependent on network calls, which could fail or hang.
- Secure workaround exists: The combination of
getTokenSilently({ ignoreCache: true }) + rotating refresh tokens provides a secure solution that passes most security audits.
Otherwise, this is the an expected behavior of the OAuth2 token rotation grant and does not represent a practical security vulnerability given the provided workaround.
In regards to the Auth0 SPA SDK:
- The
logout() function in the Auth0 SDK is responsible for clearing the client-side credentials and terminating the server-side Auth0 session.
- The observed issuance of a new refresh token is a side effect of the final token grant that occurs during the logout process with Refresh Token Rotation enabled.
- Crucially, this newly issued refresh token is never stored or used by the client application. The SDK’s
logout() method receives this token and immediately discards it as part of its session destruction process. The token exists only ephemerally in memory and is gone once the logout redirect is complete.
- For an attacker to exploit this, they would require the ability to intercept the TLS-encrypted response to the logout endpoint. An attacker with such capabilities would already have compromised the user’s session and could access far more critical data, such as the active session tokens during a login event.
Alternatively, you can consider the Management API endpoint for deleting a refresh token or the Authentication API endpoint for revoking a refresh token as long as you are able to retrieve it after receiving the response. I would recommend the latter since you can provide the refresh token itself in the request whereas the Management API one needs the token id.
If you have any other questions, let me know!
Kind Regards,
Nik