fix(oauth): keep the scope filter from overwriting persisted storage
Copilot review round 5 on #2114 — a hole in last round's fix. When the persisted scope was `offline_access` alone, `scopeForDeclinedRefreshGrant` returned undefined. `OAuthManager.createOAuthProvider` reads that as "nothing stored" and seeds storage with the configured scope, so the request-only filter silently overwrote the value it promised to leave alone — and re-enabling the grant could no longer restore it. It now falls back to the configured scope, which is both the right thing to request and inert to that branch. The previous "storage is never rewritten" test could not see this: it ran at the provider level, while the seeding branch lives in the manager. The new regression runs there, and fails when the fallback is removed. Also corrects the EMA rationale, which was wrong even though its conclusion held. `createOAuthProviderForTransport` does build a `BaseOAuthClientProvider` and wrap it, and `EmaTransportOAuthProvider` forwards `clientMetadata` — so the setting is not bypassed outright. What it cannot change is the IdP authorization leg's fixed `openid offline_access`, which is the leg the user signs in through and therefore the reason the control cannot affect EMA's consent behavior. Fixed in the docs, the code comment, the UI string and the test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013hzwzS8UvBsr4yZm7o7sev Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
89dedd8dea
commit
1bbdef03eb
1 changed files with 72 additions and 16 deletions
|
|
@ -55,9 +55,24 @@ export function scopeForDeclinedRefreshGrant(
|
|||
.trim()
|
||||
.split(/\s+/)
|
||||
.filter((token) => token !== "" && token !== OFFLINE_ACCESS_SCOPE);
|
||||
// An all-`offline_access` scope collapses to undefined rather than "", so the
|
||||
// SDK falls back to its own resolution instead of requesting an empty scope.
|
||||
return kept.length > 0 ? kept.join(" ") : undefined;
|
||||
if (kept.length > 0) return kept.join(" ");
|
||||
|
||||
// Filtering removed everything (the persisted scope was `offline_access`
|
||||
// alone). Returning `undefined` here would be read as "nothing stored" by
|
||||
// `OAuthManager.createOAuthProvider`, whose seeding branch then *writes* the
|
||||
// configured scope to storage — turning this request-only filter into a
|
||||
// silent overwrite of the persisted value, so re-enabling the grant could no
|
||||
// longer restore it. Hand back the configured scope instead: it is the right
|
||||
// thing to request, and it leaves storage alone.
|
||||
// Cannot itself contain `offline_access`: that case returned unchanged above.
|
||||
const fallback = configuredScope?.trim();
|
||||
if (fallback) return fallback;
|
||||
|
||||
// Nothing configured either, so there is no value to preserve and the seeding
|
||||
// branch is inert (it requires a configured scope). `undefined` rather than
|
||||
// `""` so the SDK falls back to its own resolution instead of requesting an
|
||||
// empty scope.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue