Skip to content

Commit dececb9

Browse files
authored
feat(codex): explicit ChatGPT-subscription vs API-key sign-in choice (#109)
Selecting the OpenAI provider in `openscience keys add` now presents an explicit choice — 'ChatGPT subscription (Codex)' (the OAuth flow, no API key) vs 'OpenAI Platform API key' — instead of dropping straight into the API-key prompt with the Codex option only discoverable as a separate pinned list item. Users who look under 'OpenAI' now find the subscription path too. Extracts a shared runCodexAuthFlow() helper so `keys add` (ChatGPT branch) and `keys signin` reach the exact same OAuth flow, removing the duplicated plugin-lookup + handlePluginAuth wiring.
1 parent 62ec54d commit dececb9

1 file changed

Lines changed: 42 additions & 10 deletions

File tree

backend/cli/src/cli/cmd/auth.ts

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ export const AuthLoginCommand = cmd({
346346
hint: {
347347
synsci: "Atlas — recommended",
348348
anthropic: "Claude Max or API key",
349-
openai: "API key (to sign in with Codex/ChatGPT, use the option above)",
349+
openai: "ChatGPT subscription (Codex) or an API key",
350350
}[x.id],
351351
})),
352352
),
@@ -359,6 +359,30 @@ export const AuthLoginCommand = cmd({
359359

360360
if (prompts.isCancel(provider)) throw new UI.CancelledError()
361361

362+
// Selecting the OpenAI provider offers two distinct auth styles: a
363+
// ChatGPT subscription (Codex OAuth, no API key) or an OpenAI Platform
364+
// API key. Present the choice explicitly instead of only pinning Codex
365+
// at the top of the list — users who look under "OpenAI" still find it.
366+
if (provider === "openai") {
367+
const style = await prompts.select({
368+
message: "How do you want to authenticate OpenAI?",
369+
options: [
370+
{
371+
value: "chatgpt",
372+
label: "ChatGPT subscription (Codex)",
373+
hint: "Plus/Pro/Business — sign in, no API key",
374+
},
375+
{ value: "apikey", label: "OpenAI Platform API key", hint: "sk-… from platform.openai.com" },
376+
],
377+
})
378+
if (prompts.isCancel(style)) throw new UI.CancelledError()
379+
if (style === "chatgpt") {
380+
await runCodexAuthFlow()
381+
return
382+
}
383+
// style === "apikey" → fall through to the API-key password prompt.
384+
}
385+
362386
const plugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider))
363387
if (plugin && plugin.auth) {
364388
const handled = await handlePluginAuth({ auth: plugin.auth }, provider)
@@ -451,6 +475,21 @@ async function backendHasCodex(): Promise<boolean | null> {
451475
}
452476
}
453477

478+
/** Run the Codex (ChatGPT subscription) OAuth flow. Shared by `keys signin` and
479+
* the ChatGPT branch of `keys add` so both reach the exact same flow. Returns
480+
* true when the flow ran, false when the codex auth plugin is unavailable. */
481+
async function runCodexAuthFlow(): Promise<boolean> {
482+
const plugin = await Plugin.list().then((x) => x.find((p) => p.auth?.provider === "openai-codex"))
483+
if (!plugin || !plugin.auth) {
484+
prompts.log.error("Codex auth plugin not available")
485+
return false
486+
}
487+
await handlePluginAuth({ auth: plugin.auth }, "openai-codex", {
488+
filterMethods: (m) => m.type === "oauth",
489+
})
490+
return true
491+
}
492+
454493
export const AuthCodexCommand = cmd({
455494
command: ["signin", "codex"],
456495
describe: "sign in with ChatGPT / Codex (Plus/Pro/Business subscription)",
@@ -490,15 +529,8 @@ export const AuthCodexCommand = cmd({
490529
}
491530
}
492531
}
493-
const plugin = await Plugin.list().then((x) => x.find((p) => p.auth?.provider === "openai-codex"))
494-
if (!plugin || !plugin.auth) {
495-
prompts.log.error("Codex auth plugin not available")
496-
prompts.outro("Done")
497-
return
498-
}
499-
await handlePluginAuth({ auth: plugin.auth }, "openai-codex", {
500-
filterMethods: (m) => m.type === "oauth",
501-
})
532+
const handled = await runCodexAuthFlow()
533+
if (!handled) prompts.outro("Done")
502534
},
503535
})
504536
},

0 commit comments

Comments
 (0)