Open History to see the last commit
1import { describe, expect, it } from "vite-plus/test";
2import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts";
3import {
4 codexAuthorizationRequest,
5 codexAuthDeliveryUrl,
6 codexAuthHandoffUrl,
7 codexCallbackUrl,
8 readCodexAuthDelivery,
9 readCodexAuthHandoff,
10} from "./codexAuthHandoff.ts";
11
12const authorizationUrl = () => {
13 const url = new URL("https://auth.openai.com/api/accounts/authorize");
14 url.search = new URLSearchParams({
15 client_id: "dynamic_agent_client",
16 response_type: "code",
17 redirect_uri: "http://127.0.0.1:54213/auth/callback",
18 state: "a".repeat(43),
19 code_challenge_method: "S256",
20 code_challenge: "b".repeat(43),
21 }).toString();
22 return url.toString();
23};
24const input = {
25 authorizationUrl: authorizationUrl(),
26 returnUrl: "https://app.t3.codes/welcome#agents:remote-environment",
27 environmentId: EnvironmentId.make("remote-environment"),
28 instanceId: ProviderInstanceId.make("work-codex"),
29 flowId: "flow-one",
30};
31const callbackUrl = `http://127.0.0.1:54213/auth/callback?state=${"a".repeat(43)}&code=one-time-code&client_id=oaiapp_test`;
32
33describe("Codex desktop handoff", () => {
34 it("keeps the hosted return route, account, and environment with the code in a fragment", () => {
35 expect(readCodexAuthHandoff(codexAuthHandoffUrl(input), false)).toEqual(input);
36 const delivery = codexAuthDeliveryUrl(input, callbackUrl);
37 expect(new URL(delivery).search).toBe("");
38 expect(readCodexAuthDelivery(delivery)).toEqual({
39 callbackUrl,
40 environmentId: input.environmentId,
41 instanceId: input.instanceId,
42 flowId: input.flowId,
43 returnHash: "#agents:remote-environment",
44 returnUrl: input.returnUrl,
45 });
46 });
47 it("rejects other handlers, schemes, arbitrary return sites, and non-OpenAI authorization", () => {
48 const link = codexAuthHandoffUrl(input);
49 expect(readCodexAuthHandoff(link, true)).toBeUndefined();
50 expect(readCodexAuthHandoff(link.replace("auth/codex", "auth/other"), false)).toBeUndefined();
51 expect(
52 readCodexAuthHandoff(
53 codexAuthHandoffUrl({ ...input, returnUrl: "https://attacker.example/welcome" }),
54 false,
55 ),
56 ).toBeUndefined();
57 expect(
58 readCodexAuthHandoff(
59 codexAuthHandoffUrl({
60 ...input,
61 authorizationUrl: input.authorizationUrl.replace("auth.openai.com", "attacker.example"),
62 }),
63 false,
64 ),
65 ).toBeUndefined();
66 });
67 it("rejects duplicated authorization parameters and non-loopback callback addresses", () => {
68 expect(() =>
69 codexAuthorizationRequest(
70 input.authorizationUrl + "&redirect_uri=http://localhost:1/auth/callback",
71 ),
72 ).toThrow();
73 const url = new URL(input.authorizationUrl);
74 url.searchParams.set("redirect_uri", "http://localhost:54213/auth/callback");
75 expect(() => codexAuthorizationRequest(url.toString())).toThrow();
76 url.searchParams.set("redirect_uri", "https://attacker.example/auth/callback");
77 expect(() => codexAuthorizationRequest(url.toString())).toThrow();
78 expect(() => codexAuthDeliveryUrl(input, callbackUrl + "&state=another")).toThrow();
79 });
80});
81
82describe("pasted Codex callback", () => {
83 const { redirectUri, state } = codexAuthorizationRequest(input.authorizationUrl);
84 const copied = callbackUrl.slice("http://".length);
85
86 it("accepts a callback copied without its scheme", () => {
87 expect(codexCallbackUrl(copied, redirectUri, state).toString()).toBe(callbackUrl);
88 });
89 it("accepts leading whitespace with or without a scheme", () => {
90 expect(codexCallbackUrl(` \t\n${callbackUrl}`, redirectUri, state).toString()).toBe(
91 callbackUrl,
92 );
93 expect(codexCallbackUrl(` \t\n${copied}`, redirectUri, state).toString()).toBe(callbackUrl);
94 });
95 it("still rejects a scheme-less callback for another address or sign-in", () => {
96 expect(() =>
97 codexCallbackUrl(copied.replace("127.0.0.1", "localhost"), redirectUri, state),
98 ).toThrow();
99 expect(() => codexCallbackUrl(copied.replace("54213", "54214"), redirectUri, state)).toThrow();
100 expect(() => codexCallbackUrl(`${copied}&state=another`, redirectUri, state)).toThrow();
101 });
102});