From 5b8da80679bcf34d6b4b0b14ea95d63471bb18d4 Mon Sep 17 00:00:00 2001 From: Project516 <138796702+Project516@users.noreply.github.com> Date: Mon, 19 Oct 2026 09:46:40 -0500 Subject: [PATCH 1/2] fix(shared): accept a pasted ChatGPT callback URL that is missing http:// --- packages/shared/src/codexAuthHandoff.test.ts | 17 +++++++++++++++++ packages/shared/src/codexAuthHandoff.ts | 5 ++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/codexAuthHandoff.test.ts b/packages/shared/src/codexAuthHandoff.test.ts index 687103cfe6e6a..6e6f225c6867a 100644 --- a/packages/shared/src/codexAuthHandoff.test.ts +++ b/packages/shared/src/codexAuthHandoff.test.ts @@ -4,6 +4,7 @@ import { codexAuthorizationRequest, codexAuthDeliveryUrl, codexAuthHandoffUrl, + codexCallbackUrl, readCodexAuthDelivery, readCodexAuthHandoff, } from "./codexAuthHandoff.ts"; @@ -77,3 +78,19 @@ describe("Codex desktop handoff", () => { expect(() => codexAuthDeliveryUrl(input, callbackUrl + "&state=another")).toThrow(); }); }); + +describe("pasted Codex callback", () => { + const { redirectUri, state } = codexAuthorizationRequest(input.authorizationUrl); + const copied = callbackUrl.slice("http://".length); + + it("accepts a callback copied without its scheme", () => { + expect(codexCallbackUrl(copied, redirectUri, state).toString()).toBe(callbackUrl); + }); + it("still rejects a scheme-less callback for another address or sign-in", () => { + expect(() => + codexCallbackUrl(copied.replace("127.0.0.1", "localhost"), redirectUri, state), + ).toThrow(); + expect(() => codexCallbackUrl(copied.replace("54213", "54214"), redirectUri, state)).toThrow(); + expect(() => codexCallbackUrl(`${copied}&state=another`, redirectUri, state)).toThrow(); + }); +}); diff --git a/packages/shared/src/codexAuthHandoff.ts b/packages/shared/src/codexAuthHandoff.ts index 7f0e4ccd183a4..d1957481ee7a3 100644 --- a/packages/shared/src/codexAuthHandoff.ts +++ b/packages/shared/src/codexAuthHandoff.ts @@ -56,8 +56,11 @@ export function codexAuthorizationRequest(value: string) { } export function codexCallbackUrl(value: string, redirectUri: string, state: string) { - const callback = new URL(value); const expected = new URL(redirectUri); + // Browsers can hide `http://` in the address bar, so a pasted callback may lack it. + const callback = new URL( + /^[a-z][a-z\d+.-]*:\/\//iu.test(value) ? value : `${expected.protocol}//${value}`, + ); const states = callback.searchParams.getAll("state"); const codes = callback.searchParams.getAll("code"); const errors = callback.searchParams.getAll("error"); From 0037262246856fd93244ea71d13f8356d86ced15 Mon Sep 17 00:00:00 2001 From: Project516 <138796702+Project516@users.noreply.github.com> Date: Mon, 19 Oct 2026 10:02:39 -0500 Subject: [PATCH 2/2] fix(shared): preserve leading whitespace in pasted Codex callbacks --- packages/shared/src/codexAuthHandoff.test.ts | 6 ++++++ packages/shared/src/codexAuthHandoff.ts | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/codexAuthHandoff.test.ts b/packages/shared/src/codexAuthHandoff.test.ts index 6e6f225c6867a..30693b60e5c87 100644 --- a/packages/shared/src/codexAuthHandoff.test.ts +++ b/packages/shared/src/codexAuthHandoff.test.ts @@ -86,6 +86,12 @@ describe("pasted Codex callback", () => { it("accepts a callback copied without its scheme", () => { expect(codexCallbackUrl(copied, redirectUri, state).toString()).toBe(callbackUrl); }); + it("accepts leading whitespace with or without a scheme", () => { + expect(codexCallbackUrl(` \t\n${callbackUrl}`, redirectUri, state).toString()).toBe( + callbackUrl, + ); + expect(codexCallbackUrl(` \t\n${copied}`, redirectUri, state).toString()).toBe(callbackUrl); + }); it("still rejects a scheme-less callback for another address or sign-in", () => { expect(() => codexCallbackUrl(copied.replace("127.0.0.1", "localhost"), redirectUri, state), diff --git a/packages/shared/src/codexAuthHandoff.ts b/packages/shared/src/codexAuthHandoff.ts index d1957481ee7a3..d0146bf767959 100644 --- a/packages/shared/src/codexAuthHandoff.ts +++ b/packages/shared/src/codexAuthHandoff.ts @@ -57,9 +57,10 @@ export function codexAuthorizationRequest(value: string) { export function codexCallbackUrl(value: string, redirectUri: string, state: string) { const expected = new URL(redirectUri); + const pasted = value.trimStart(); // Browsers can hide `http://` in the address bar, so a pasted callback may lack it. const callback = new URL( - /^[a-z][a-z\d+.-]*:\/\//iu.test(value) ? value : `${expected.protocol}//${value}`, + /^[a-z][a-z\d+.-]*:\/\//iu.test(pasted) ? pasted : `${expected.protocol}//${pasted}`, ); const states = callback.searchParams.getAll("state"); const codes = callback.searchParams.getAll("code");