I added a github issue, but not sure if it’s better to ask here as well.
I noticed the auth0-spa-js lib doesn’t properly rotate refresh tokens with MRRT if the requests are sent in parallel since the lock on getSilentToken is per audience. Has anyone ran into something similar or is it possible I’m missing a config? Ran into this using MRRT in the angular auth0 lib for a landing SPA that checks various backends across different audiences.
opened 05:46PM - 16 Jul 26 UTC
bug
### Checklist
- [x] The issue can be reproduced in the [auth0-spa-js sample app… ](https://github.com/auth0-samples/auth0-javascript-samples/tree/master/01-Login) (or N/A).
- [x] I have looked into the [Readme](https://github.com/auth0/auth0-spa-js#readme), [Examples](https://github.com/auth0/auth0-spa-js/blob/main/EXAMPLES.md), and [FAQ](https://github.com/auth0/auth0-spa-js/blob/main/FAQ.md) and have not found a suitable solution or answer.
- [x] I have looked into the [documentation](https://auth0.com/docs/libraries/auth0-single-page-app-sdk) and [API documentation](https://auth0.github.io/auth0-spa-js/), and have not found a suitable solution or answer.
- [x] I have searched the [issues](https://github.com/auth0/auth0-spa-js/issues) and have not found a suitable solution or answer.
- [x] I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer.
- [x] I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md).
### Description
If a client tries to get 2 or more access tokens at the same time with MRRT and token rotation on, the SPA uses the same refresh token for all POST requests to /auth0/token. This violates the reuse policy, causing future usages of new rotated refresh tokens to get invalidated.
Reuse Overlap / leeway lets the requests succeed temporarily. Once past the reuse period, trying to get new tokens using refresh tokens related to the original token return 'invalid_grant'.
### Reproduction
1. A SPA with Refresh Token Rotation on (set reuse window to 3, easy to observe if set to 0)
2. Register multiple API audiences with MRRT that have offline_access enabled
3. Log in to the SPA
4. Request tokens for 2+ audiences concurrently using `getTokenSilently`
5. Observe initial requests succeed within the reuse window
6. Wait for reuse window to lapse, then attempt to get new tokens using `getTokenSilently`
7. `invalid_grant`
See patch for https://github.com/auth0-samples/auth0-javascript-samples.git 9a35820af310448ca9b1dc58d2e31ca4e1065657 (master)
[mrrt-repro.patch](https://github.com/user-attachments/files/30096992/mrrt-repro.patch)
### Additional context
Workaround: in angular auth0 spa, `useRefreshTokensFallback: true` allows recovery from this state by getting a new base token via an iframe, as does redirecting the user to /authorize to get a fresh grant.
Should there be an option to serialize token requests when rotation is on? Or is the fix specific to the angular-auth0 http-interceptor? (I believe rotation is required for SPA's to use refresh tokens, so parallelization of MRRT in a SPA will always run into this)
Root cause seems to stem from the `(client_id, audience)` lock from #1408
Timeline example I've observed:
```
15:53:51.071 authorization_code (login) — -> e08cc1 200 base RT issued
15:53:51.317 refresh_token aud-A e08cc1 -> b04dc7 200 ┐
15:53:51.317 refresh_token aud-B e08cc1 -> bd45d2 200 │ 5 concurrent grants,
15:53:51.317 refresh_token aud-C e08cc1 -> 9a32b1 200 │ same base RT e08cc1,
15:53:51.318 refresh_token aud-D e08cc1 -> db39fc 200 │ family forks into 5
15:53:51.318 refresh_token aud-E e08cc1 -> cfbfb8 200 ┘
... ~11 min later, on next refresh of aud-B's forked child ...
16:05:29.602 refresh_token aud-B bd45d2 -> — 403 invalid_grant (family revoked)
16:05:30.578 authorization_code (recover) — -> 1b6afe 200 (silent iframe re-auth)
... repeats every refresh cycle ...
16:15:09.082 refresh_token aud-B 1b6afe -> — 403 invalid_grant (revoked again)
16:15:10.441 authorization_code (recover) — -> 294245 200
```
### auth0-spa-js version
2.19.2
### Which framework are you using (React, Angular, Vue...)?
Angular
### Framework version
auth0 2.9.0, angular 21.2
### Which browsers have you tested in?
Firefox, Chrome