diff --git a/CHANGELOG.md b/CHANGELOG.md index 741e32f8055..86a87e0e704 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- OpenAI Codex OAuth/auth URL integrity: stop rewriting Pi-generated OAuth authorize URLs during browser handoff so provider-signed authorization requests remain valid; keep post-login missing-scope detection for actionable remediation. Thanks @vignesh for the report. - Onboarding/headless Linux daemon probe hardening: treat `systemctl --user is-enabled` probe failures as non-fatal during daemon install flow so onboarding no longer crashes on SSH/headless VPS environments before showing install guidance. (#37297) Thanks @acarbajal-web. - Memory/QMD mcporter Windows spawn hardening: when `mcporter.cmd` launch fails with `spawn EINVAL`, retry via bare `mcporter` shell resolution so QMD recall can continue instead of falling back to builtin memory search. (#27402) Thanks @i0ivi0i. - Tools/web_search Brave language-code validation: align `search_lang` handling with Brave-supported codes (including `zh-hans`, `zh-hant`, `en-gb`, and `pt-br`), map common alias inputs (`zh`, `ja`) to valid Brave values, and reject unsupported codes before upstream requests to prevent 422 failures. (#37260) Thanks @heyanming. diff --git a/src/commands/openai-codex-oauth.test.ts b/src/commands/openai-codex-oauth.test.ts index c5fe6d535ba..8798853c8f4 100644 --- a/src/commands/openai-codex-oauth.test.ts +++ b/src/commands/openai-codex-oauth.test.ts @@ -104,7 +104,7 @@ describe("loginOpenAICodexOAuth", () => { expect(runtime.error).not.toHaveBeenCalled(); }); - it("augments OAuth authorize URL with required OpenAI API scopes", async () => { + it("passes through Pi-provided OAuth authorize URL without mutation", async () => { const creds = { provider: "openai-codex" as const, access: "access-token", @@ -130,14 +130,9 @@ describe("loginOpenAICodexOAuth", () => { expect(onAuthSpy).toHaveBeenCalledTimes(1); const event = onAuthSpy.mock.calls[0]?.[0] as { url: string }; - const scopes = new Set((new URL(event.url).searchParams.get("scope") ?? "").split(/\s+/)); - expect(scopes.has("openid")).toBe(true); - expect(scopes.has("profile")).toBe(true); - expect(scopes.has("email")).toBe(true); - expect(scopes.has("offline_access")).toBe(true); - expect(scopes.has("api.responses.write")).toBe(true); - expect(scopes.has("model.request")).toBe(true); - expect(scopes.has("api.model.read")).toBe(true); + expect(event.url).toBe( + "https://auth.openai.com/oauth/authorize?scope=openid+profile+email+offline_access&state=abc", + ); }); it("reports oauth errors and rethrows", async () => { diff --git a/src/commands/openai-codex-oauth.ts b/src/commands/openai-codex-oauth.ts index c9290d5617e..ea2098e3380 100644 --- a/src/commands/openai-codex-oauth.ts +++ b/src/commands/openai-codex-oauth.ts @@ -10,46 +10,6 @@ import { const OPENAI_RESPONSES_ENDPOINT = "https://api.openai.com/v1/responses"; const OPENAI_RESPONSES_WRITE_SCOPE = "api.responses.write"; -const OPENAI_REQUIRED_OAUTH_SCOPES = [ - OPENAI_RESPONSES_WRITE_SCOPE, - "model.request", - "api.model.read", -] as const; - -function augmentOpenAIOAuthScopes(authUrl: string): string { - try { - const parsed = new URL(authUrl); - const scopeParam = parsed.searchParams.get("scope"); - if (!scopeParam) { - return authUrl; - } - const scopes = scopeParam - .split(/\s+/) - .map((scope) => scope.trim()) - .filter(Boolean); - if (scopes.length === 0) { - return authUrl; - } - const seen = new Set(scopes.map((scope) => scope.toLowerCase())); - let changed = false; - for (const requiredScope of OPENAI_REQUIRED_OAUTH_SCOPES) { - const normalized = requiredScope.toLowerCase(); - if (seen.has(normalized)) { - continue; - } - scopes.push(requiredScope); - seen.add(normalized); - changed = true; - } - if (!changed) { - return authUrl; - } - parsed.searchParams.set("scope", scopes.join(" ")); - return parsed.toString(); - } catch { - return authUrl; - } -} function extractResponsesScopeErrorMessage(status: number, bodyText: string): string | null { if (status !== 401) { @@ -124,15 +84,9 @@ export async function loginOpenAICodexOAuth(params: { openUrl, localBrowserMessage: localBrowserMessage ?? "Complete sign-in in browser…", }); - const onAuth = async (event: { url: string }) => { - await baseOnAuth({ - ...event, - url: augmentOpenAIOAuthScopes(event.url), - }); - }; const creds = await loginOpenAICodex({ - onAuth, + onAuth: baseOnAuth, onPrompt, onProgress: (msg) => spin.update(msg), });