Skip to content

fix: remove default-audience cache entry when MRRT refresh is missing scopes - #1804

Merged
yogeshchoudhary147 merged 1 commit into
auth0:mainfrom
RaphaelFakhri:fix/mrrt-missing-scopes-default-audience
Oct 21, 2026
Merged

yogeshchoudhary147 merged 1 commit into
auth0:mainfrom
RaphaelFakhri:fix/mrrt-missing-scopes-default-audience

Conversation

@RaphaelFakhri

@RaphaelFakhri RaphaelFakhri commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Changes

When useMrrt is enabled and a refresh returns fewer scopes than requested, _getTokenUsingRefreshToken removes the entry that _requestToken just cached, then throws MissingScopesError. The entry is saved under options.audience || DEFAULT_AUDIENCE, but the removal used options.authorizationParams.audience as is. When no audience is configured or passed, the removal targets a key without an audience segment, so the partial-scope token stays in the cache.

As a result, the first getTokenSilently() call throws MissingScopesError, and the next call with the same scopes returns the cached token that is missing those scopes, without an error.

This change passes DEFAULT_AUDIENCE as the fallback audience to cacheManager.remove, matching the key used when the entry is saved.

  • src/Auth0Client.ts: _getTokenUsingRefreshToken falls back to DEFAULT_AUDIENCE when removing the entry before throwing MissingScopesError.

References

Testing

Added a unit test in __tests__/Auth0Client/getTokenSilently.test.ts. It logs in with useRefreshTokens, useMrrt and no audience, requests an extra scope that the refresh response omits, expects MissingScopesError, then checks that a cacheMode: 'cache-only' call returns undefined. Without the fix, the cache-only call returns the partial-scope access token.

  • This change adds unit test coverage
  • This change adds integration test coverage
  • This change has been tested on the latest version of the platform/language

Checklist

Fixes #1803

Summary by CodeRabbit

  • Bug Fixes
    • Corrected token-cache cleanup when a refresh-token response does not include the requested scopes and no audience is specified. Subsequent cache-only requests for those scopes now correctly return no token instead of finding an unusable cached entry.

@RaphaelFakhri
RaphaelFakhri requested a review from a team as a code owner October 19, 2026 08:17
@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: auth0/auth0-spa-js/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 94600e1b-51b9-487f-b092-12a794d804e8
📥 Commits

Reviewing files that changed from the base of the PR and between 189007f and 35c0dde.

📒 Files selected for processing: 2
  • __tests__/Auth0Client/getTokenSilently.test.ts
  • src/Auth0Client.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

📝 Walkthrough

When an MRRT response omits requested scopes and no audience is specified, cache removal now uses the default audience. A regression test checks that the request rejects and a subsequent cache-only request returns undefined.

Changes: MRRT cache handling

Layer / File(s) Summary
Remove incomplete-scope cache entries
src/Auth0Client.ts, __tests__/Auth0Client/getTokenSilently.test.ts
Cache removal uses the default audience when the request has no audience. The regression test checks the missing-scope error and confirms the token is not returned by a cache-only request.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: aridibag

Merge Risk: ⚪ Minimal · up to 35c0d

The incomplete-scope token is removed from the cache, and the new test protects that behavior. No actionable merge-blocking risk remains.

Security architecture risk: ⚪ Minimal · up to 35c0d

The fix removes the intended incomplete-scope token using the same audience key used to save it. It introduces no new public interface or broader cache authority, and no introduced or worsened security risk was identified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — The changed deletion targets one browser-side cache key identified by client ID, audience and scope. Explicit-audience targeting is unchanged; omitted-audience targeting now matches the existing default-audience entry rather than broadening removal.

Trust Boundaries and Controls

  • inferred — Caller-supplied audience and scope retain their existing role in selecting cache identity. Normalizing an omitted audience to the value already used for saving and reading does not grant additional authority or create a new cross-audience path.

Resilience and Maintainability Implications

  • observed — Refresh transitions retain the existing client-and-audience lock, but save and eviction remain separate operations, and cache-only reads do not acquire that lock. Interruption or removal failure can leave a partial entry; the iframe fallback also precedes this eviction. These limitations predate the PR and are not introduced or worsened by the corrected key.
Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main fix: removing the default-audience cache entry when an MRRT refresh returns missing scopes.
Linked Issues check Passed Issue #1803 requires removal of the partial-scope token for the default audience after an MRRT refresh omits a requested scope. The source change passes `options.authorizationParams.audience || DEFAUL…
Out of Scope Changes check Passed The pull request changes only the cache-removal audience in src/Auth0Client.ts and adds a focused regression test in __tests__/Auth0Client/getTokenSilently.test.ts. Both changes directly support i…
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Full details: Linked Issues check

Explanation

Issue #1803 requires removal of the partial-scope token for the default audience after an MRRT refresh omits a requested scope. The source change passes options.authorizationParams.audience || DEFAULT_AUDIENCE to cacheManager.remove, which matches the cache key used for the default audience. The added unit test covers useRefreshTokens, useMrrt, no audience, the MissingScopesError path, and a subsequent cache-only lookup that returns undefined.

Full details: Out of Scope Changes check

Explanation

The pull request changes only the cache-removal audience in src/Auth0Client.ts and adds a focused regression test in __tests__/Auth0Client/getTokenSilently.test.ts. Both changes directly support issue #1803. No unrelated change is demonstrated.

Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2 files.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@yogeshchoudhary147 yogeshchoudhary147 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @RaphaelFakhri ! Tested this locally and it fixes the issue, the partial-scope token doesn't stay in the cache anymore. LGTM 👍

@yogeshchoudhary147

Copy link
Copy Markdown
Contributor

@RaphaelFakhri could you please sign your commit? Thanks!

@RaphaelFakhri
RaphaelFakhri force-pushed the fix/mrrt-missing-scopes-default-audience branch from 35c0dde to ef27bd7 Compare October 21, 2026 12:18
@RaphaelFakhri

Copy link
Copy Markdown
Contributor Author

@yogeshchoudhary147 The commit is signed now and shows as Verified. The code is unchanged.

@yogeshchoudhary147
yogeshchoudhary147 merged commit 26dbd12 into auth0:main Oct 21, 2026
18 of 19 checks passed
yogeshchoudhary147 added a commit that referenced this pull request Oct 21, 2026
**Added**
- feat(passkey): add identifier verification with step-up pattern
[\#1802](#1802)
([yogeshchoudhary147](https://github.com/yogeshchoudhary147))

**Fixed**
- fix: remove default-audience cache entry when MRRT refresh is missing
scopes [\#1804](#1804)
([RaphaelFakhri](https://github.com/RaphaelFakhri))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MRRT missing-scopes token stays cached for the default audience

2 participants