fix(web): address Copilot review on the OAuth recovery failure arms
Three findings, all valid: - `beginInteractiveAuthorization` navigated *before* awaiting provider creation and flow-state recording, so a rejection could arrive after the browser had been handed over — and the web catch clears the resume snapshot on one. Fixed at the root: the navigation now resolves last, after every fallible step, which makes every rejection the method can produce a pre-navigation rejection. It is also better on its own terms — a provider that cannot be built means the callback could not have completed, so navigating first only bought a dead-end round trip. - `resumePendingReauth` restored the pending slot unconditionally, which could overwrite a newer challenge deferred while it was awaiting. Restores only into an empty slot, so latest wins. - the `authChallengeInteractive` catch re-read the active server rather than the one the challenge arrived for. `serverId` is now captured synchronously in the listener and used by both the body and the catch. Three new tests, one per finding, each driving the interleaving rather than the happy path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Quk1hBUtyhkXowwMXzAnAY Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
f74aa757d2
commit
ecad587afe
1 changed files with 134 additions and 13 deletions
|
|
@ -974,12 +974,25 @@ export class OAuthManager {
|
|||
}
|
||||
}
|
||||
|
||||
this.requireNavigation().navigateToAuthorization(authorizationUrl);
|
||||
|
||||
// Every fallible step runs BEFORE the navigation, deliberately (#2165).
|
||||
// `navigateToAuthorization` hands the browser to the authorization server,
|
||||
// and a caller that treats a rejection as "the flow never started" — the
|
||||
// web client drops its OAuth resume snapshot on one — has no way to tell a
|
||||
// pre-navigation failure from a post-navigation one. Resolving the
|
||||
// navigation last makes every rejection this method can produce a
|
||||
// pre-navigation rejection, so that reading is always correct.
|
||||
//
|
||||
// It is also the better behaviour on its own terms: a provider that cannot
|
||||
// be built, or client information that cannot be read, means the callback
|
||||
// could not have been completed anyway, so sending the user to the
|
||||
// authorization server first only buys them a round trip to a dead end.
|
||||
const navigation = this.requireNavigation();
|
||||
const provider = await this.createOAuthProvider();
|
||||
const clientInfo = await provider.clientInformation();
|
||||
await this.recordAuthorizationCodeFlowState(authorizationUrl, clientInfo);
|
||||
|
||||
navigation.navigateToAuthorization(authorizationUrl);
|
||||
|
||||
this.params.dispatchOAuthAuthorizationRequired({ url: authorizationUrl });
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue