galaxyproject / galaxyproject/loom

Add Anthropic OAuth (Claude Pro/Max) sign-in to Orbit alongside API-key auth

Open
#29 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
14
Forks
12
Avg merge
6d 5h
Merged PRs (30d)
17

Description

## 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

1. **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.

2. **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)`.

3. **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.

4. **Preferences modal**:
- Show signed-in state (\"Signed in as ``\" 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).

5. **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.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.