Motivation
Orbit currently requires users to paste an Anthropic API key into the welcome screen / Preferences. For Claude Pro / Max subscribers, OAuth-based sign-in (the same flow Claude Code uses) would be a much better first-run experience — no console trip, no key management, no leaked-secret risk. It also opens the door to GitHub Copilot, Google Gemini CLI, and OpenAI Codex sign-ins via the same plumbing.
Most of the work is already in pi-ai
@mariozechner/pi-ai/utils/oauth/anthropic.ts exposes the full PKCE flow:
loginAnthropic({ onAuth, onPrompt, onProgress, onManualCodeInput }) — opens a Node HTTP callback server, generates the auth URL, waits for the redirect, exchanges the code for tokens, returns OAuthCredentials.
refreshAnthropicToken(refreshToken) — token rotation.
anthropicOAuthProvider — OAuthProviderInterface registration helper.
Sibling providers exist for GitHub Copilot, Gemini CLI, Antigravity, and OpenAI Codex — the same surface.
pi-coding-agent already wires OAuth into its auth storage:
core/model-registry.ts calls registerOAuthProvider.
authStorage.getOAuthProviders() enumerates registered providers.
migrations.js migrates legacy oauth.json → auth.json with {type: \"oauth\", ...creds} records.
auth.json already supports a mixed store of apiKey + oauth entries.
So the brain side is essentially free. 401 → refresh-and-retry should already be in pi-coding-agent's request pipeline.
What Orbit needs to add
-
Main-process auth handler (~30 lines, new file app/src/main/auth-handler.ts):
- Calls
loginAnthropic({ onAuth: ({url}) => shell.openExternal(url), onPrompt: ..., onProgress: ... }).
- The
onAuth(url) fires once the local callback server is up; Orbit launches the user's default browser.
- When
loginAnthropic resolves, persist the credentials via pi-coding-agent's authStorage.
- Single in-flight lock so multiple windows don't fight.
-
Three IPC endpoints in ipc-handlers.ts:
auth:login(provider) — kicks off the flow; resolves on success or error.
auth:status() — returns the current sign-in state per provider (signed in / handle / expiry; or none).
auth:logout(provider) — clear credentials.
- Preload exposure:
window.orbit.signIn(provider), window.orbit.authStatus(), window.orbit.signOut(provider).
-
Welcome screen (index.html + app.ts):
- Add a primary "Sign in with Claude" button above the API-key field.
- Keep the API-key input as a fallback (corporate networks, custom endpoints, sandboxed deployments).
- On click, call
signIn(\"anthropic\"), show a small spinner while waiting, dismiss the welcome on success.
-
Preferences modal:
- Show signed-in state ("Signed in as
<email>" or "Using API key (last 4: …)") with a "Sign out" link.
- Sign-in button below for users who want to swap from API-key to OAuth (or vice versa).
-
Migration on first run: invoke migrations.js's legacy-oauth migrator at agent startup so existing pi-coding-agent users on this machine pick up their tokens automatically.
Pitfalls / things to plan for
- Random callback port —
loginAnthropic picks a free local port; Linux/macOS will prompt for a firewall exception once. On Windows, the first launch shows a firewall dialog. Mention this in the welcome flow if helpful.
- Corporate networks that block
claude.ai/oauth — keep the API-key path as a permanent fallback, do not remove it.
- "Only intended for CLI use" — pi-ai's note refers to the
http.createServer callback; Electron's main process is Node-side, so this is fine. Do not try to call loginAnthropic from the renderer.
- Token-refresh visibility — pi-coding-agent should refresh transparently on 401, but if it surfaces an error to the agent shell when the refresh token also expires, Orbit should display "Sign-in expired — please sign in again" instead of letting it silently break the next turn.
Out of scope / future
- GitHub Copilot, Gemini CLI, OpenAI Codex sign-ins — same code path; once Anthropic works, these are 1-line registrations in the auth handler. File as a follow-up issue once the Anthropic flow is shipping.
- An "Account" tab in Preferences listing all providers + their statuses. Nice-to-have; not blocking the MVP.
Estimate
Half a day to a day for a polished MVP — the OAuth callback orchestration is the only "real" code, everything else is wiring buttons and state pills.
Happy to put up a PR for this once approved if no one else has it queued.
Motivation
Orbit currently requires users to paste an Anthropic API key into the welcome screen / Preferences. For Claude Pro / Max subscribers, OAuth-based sign-in (the same flow Claude Code uses) would be a much better first-run experience — no console trip, no key management, no leaked-secret risk. It also opens the door to GitHub Copilot, Google Gemini CLI, and OpenAI Codex sign-ins via the same plumbing.
Most of the work is already in pi-ai
@mariozechner/pi-ai/utils/oauth/anthropic.tsexposes the full PKCE flow:loginAnthropic({ onAuth, onPrompt, onProgress, onManualCodeInput })— opens a Node HTTP callback server, generates the auth URL, waits for the redirect, exchanges the code for tokens, returnsOAuthCredentials.refreshAnthropicToken(refreshToken)— token rotation.anthropicOAuthProvider—OAuthProviderInterfaceregistration helper.Sibling providers exist for GitHub Copilot, Gemini CLI, Antigravity, and OpenAI Codex — the same surface.
pi-coding-agentalready wires OAuth into its auth storage:core/model-registry.tscallsregisterOAuthProvider.authStorage.getOAuthProviders()enumerates registered providers.migrations.jsmigrates legacyoauth.json→auth.jsonwith{type: \"oauth\", ...creds}records.auth.jsonalready supports a mixed store ofapiKey+oauthentries.So the brain side is essentially free. 401 → refresh-and-retry should already be in pi-coding-agent's request pipeline.
What Orbit needs to add
Main-process auth handler (~30 lines, new file
app/src/main/auth-handler.ts):loginAnthropic({ onAuth: ({url}) => shell.openExternal(url), onPrompt: ..., onProgress: ... }).onAuth(url)fires once the local callback server is up; Orbit launches the user's default browser.loginAnthropicresolves, persist the credentials via pi-coding-agent'sauthStorage.Three IPC endpoints in
ipc-handlers.ts:auth:login(provider)— kicks off the flow; resolves on success or error.auth:status()— returns the current sign-in state per provider (signed in / handle / expiry; or none).auth:logout(provider)— clear credentials.window.orbit.signIn(provider),window.orbit.authStatus(),window.orbit.signOut(provider).Welcome screen (
index.html+app.ts):signIn(\"anthropic\"), show a small spinner while waiting, dismiss the welcome on success.Preferences modal:
<email>" or "Using API key (last 4: …)") with a "Sign out" link.Migration on first run: invoke
migrations.js's legacy-oauth migrator at agent startup so existing pi-coding-agent users on this machine pick up their tokens automatically.Pitfalls / things to plan for
loginAnthropicpicks a free local port; Linux/macOS will prompt for a firewall exception once. On Windows, the first launch shows a firewall dialog. Mention this in the welcome flow if helpful.claude.ai/oauth— keep the API-key path as a permanent fallback, do not remove it.http.createServercallback; Electron's main process is Node-side, so this is fine. Do not try to callloginAnthropicfrom the renderer.Out of scope / future
Estimate
Half a day to a day for a polished MVP — the OAuth callback orchestration is the only "real" code, everything else is wiring buttons and state pills.
Happy to put up a PR for this once approved if no one else has it queued.