fix(oauth): proxy-aware fetch for OpenAI Codex token exchange
Node.js native fetch() ignores HTTP_PROXY / HTTPS_PROXY env vars. Users behind a proxy (e.g. Hong Kong, mainland China) get 403 'unsupported_country_region_territory' during token exchange even though the browser OAuth flow succeeds through their system proxy. Wrap the loginOpenAICodex() call with withProxyFetch(), which temporarily patches globalThis.fetch with an undici ProxyAgent-backed implementation when proxy env vars are detected. The original fetch is restored after the call completes. No-op when no proxy is configured or undici is unavailable. Fixes #29418
This commit is contained in:
parent
598f1826d8
commit
34cf87517a
@ -7,6 +7,51 @@ import {
|
||||
runOpenAIOAuthTlsPreflight,
|
||||
} from "./provider-openai-codex-oauth-tls.js";
|
||||
|
||||
/**
|
||||
* Node.js native fetch() ignores HTTP_PROXY / HTTPS_PROXY env vars.
|
||||
* This helper temporarily patches globalThis.fetch with a proxy-aware
|
||||
* implementation (via undici ProxyAgent) for the duration of `fn()`,
|
||||
* then restores the original fetch. No-op when no proxy is configured
|
||||
* or undici is unavailable.
|
||||
*/
|
||||
async function withProxyFetch<T>(fn: () => Promise<T>): Promise<T> {
|
||||
const proxyUrl =
|
||||
process.env.HTTPS_PROXY ||
|
||||
process.env.https_proxy ||
|
||||
process.env.HTTP_PROXY ||
|
||||
process.env.http_proxy ||
|
||||
process.env.ALL_PROXY ||
|
||||
process.env.all_proxy;
|
||||
if (!proxyUrl) return fn();
|
||||
|
||||
let restore: (() => void) | undefined;
|
||||
try {
|
||||
const { createRequire } = await import("node:module");
|
||||
const require_ = createRequire(import.meta.url);
|
||||
// undici is a transitive dependency of OpenClaw (via Node internals / direct dep)
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const undici = require_("undici") as typeof import("undici");
|
||||
const agent = new undici.ProxyAgent(proxyUrl);
|
||||
const origFetch = globalThis.fetch;
|
||||
globalThis.fetch = ((url: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) =>
|
||||
undici.fetch(url as Parameters<typeof undici.fetch>[0], {
|
||||
...(init as Parameters<typeof undici.fetch>[1]),
|
||||
dispatcher: agent,
|
||||
})) as typeof fetch;
|
||||
restore = () => {
|
||||
globalThis.fetch = origFetch;
|
||||
};
|
||||
} catch {
|
||||
// undici not available — proceed with unpatched fetch
|
||||
}
|
||||
|
||||
try {
|
||||
return await fn();
|
||||
} finally {
|
||||
restore?.();
|
||||
}
|
||||
}
|
||||
|
||||
export async function loginOpenAICodexOAuth(params: {
|
||||
prompter: WizardPrompter;
|
||||
runtime: RuntimeEnv;
|
||||
@ -49,11 +94,13 @@ export async function loginOpenAICodexOAuth(params: {
|
||||
localBrowserMessage: localBrowserMessage ?? "Complete sign-in in browser…",
|
||||
});
|
||||
|
||||
const creds = await loginOpenAICodex({
|
||||
onAuth: baseOnAuth,
|
||||
onPrompt,
|
||||
onProgress: (msg: string) => spin.update(msg),
|
||||
});
|
||||
const creds = await withProxyFetch(() =>
|
||||
loginOpenAICodex({
|
||||
onAuth: baseOnAuth,
|
||||
onPrompt,
|
||||
onProgress: (msg: string) => spin.update(msg),
|
||||
}),
|
||||
);
|
||||
spin.stop("OpenAI OAuth complete");
|
||||
return creds ?? null;
|
||||
} catch (err) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user