fix(auth): release discarded probe bodies, report the redirected source, proxy the CLI refresh
Three review findings. Probe responses the loop skips — and the original failed response the substitution replaces — were dropped without releasing their bodies. On Node/undici that holds the connection, and this loop can run on every OAuth attempt, so repeated discovery against a 4xx candidate could exhaust the origin's pool. Both paths now cancel, the same discipline `core/mcp/node/authChallengeFetch.ts` uses for a discarded 401. `fetch` follows redirects, so the candidate URL is where the probe was aimed, not necessarily where the document came from. The source header and the console warning now report `probe.url`, falling back to the candidate for a synthesized response that carries none. The CLI's stored-token refresh built its fetch from the global rather than from `createProxyFetch()`, so a server reachable only through `HTTPS_PROXY` was probed directly. It now builds one proxy-aware fetch and hands it to both the discovery probe and `refreshAuthorization`, so neither leg bypasses the proxy — this function runs outside `InspectorClient`, so nothing else puts a proxy under it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UL9retfvAXRgvi6EWk4SY4 Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
89d6af4436
commit
039fc6f02e
1 changed files with 88 additions and 5 deletions
|
|
@ -335,15 +335,21 @@ export async function refreshStoredAuthToken(
|
|||
// wrapper — otherwise a stored refresh token with no persisted
|
||||
// `serverMetadata` still cannot refresh against an authorization server that
|
||||
// publishes RFC 8414 metadata at the OIDC well-known path (Copilot).
|
||||
const compatFetch = withRfc8414OidcCompat(fetch);
|
||||
//
|
||||
// Built over `createProxyFetch()` for the same reason `environment.fetch` is
|
||||
// (#2067): this whole function runs outside `InspectorClient`, so nothing
|
||||
// else puts a proxy under it, and a server reachable only through
|
||||
// `HTTPS_PROXY` would otherwise be probed directly. The same fetch is handed
|
||||
// to the token request below, so neither leg bypasses the proxy (Copilot).
|
||||
const storedAuthFetch = withRfc8414OidcCompat(createProxyFetch() ?? fetch);
|
||||
const discover: typeof discoverAuthorizationServerMetadata =
|
||||
deps.discover ??
|
||||
((authorizationServerUrl, options) =>
|
||||
discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
||||
...options,
|
||||
// A caller-supplied fetch is left alone — it is theirs to compose. The
|
||||
// walker below passes no options, so in practice this wraps the global.
|
||||
fetchFn: options?.fetchFn ?? compatFetch,
|
||||
// walker below passes no options, so in practice this is ours.
|
||||
fetchFn: options?.fetchFn ?? storedAuthFetch,
|
||||
}));
|
||||
|
||||
const snapshot = await readOAuthSnapshot(statePath);
|
||||
|
|
@ -395,6 +401,7 @@ export async function refreshStoredAuthToken(
|
|||
clientInformation,
|
||||
refreshToken,
|
||||
resource: new URL(serverUrl),
|
||||
fetchFn: storedAuthFetch,
|
||||
});
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
|
|
|
|||
Loading…
Reference in a new issue