Skip to content

feat: Multi-Account OAuth Rotation with Settings UI #9068

@mguttmann

Description

@mguttmann

Problem Statement

Users with Claude Max subscriptions frequently hit rate limits, causing workflow interruptions. While OpenCode supports OAuth login, there was no way to:

  1. Login with multiple accounts for the same provider
  2. Manually switch between accounts
  3. See rate limit usage across accounts
  4. Automatically rotate to another account when one hits limits
  5. Delete individual accounts when no longer needed

Additionally, the desktop app lacked a centralized settings interface for managing providers and viewing usage statistics.

Solution Overview

This feature introduces comprehensive multi-account OAuth support with:

  • Automatic rotation when accounts hit rate limits
  • Manual switching via CLI and desktop UI
  • Usage statistics display (currently Anthropic only)
  • Delete individual accounts via CLI and desktop UI
  • New Settings menu in desktop app

Feature Details

1. Multi-Account OAuth Rotation (Backend)

Core Changes:

  • Auth.OAuthPool.setActive(providerID, namespace, recordID) - Set active account
  • Auth.OAuthPool.removeRecord(providerID, recordID) - Delete individual account
  • Auth.OAuthPool.snapshot() - Now returns activeID for credential selection
  • Auth.OAuthPool.getAccounts() - Correctly identifies active account
  • fetchAnthropicUsage() - Respects provider.active[namespace]

Credential Selection Flow:

1. snapshot() returns { records, orderedIDs, activeID }
2. candidates = [activeID, ...other accounts]
3. pickNextCandidate() selects first non-cooldown account
4. On 429 → account gets cooldown, next account used

2. API Endpoints

POST /auth/active

Request:  { "providerID": "anthropic", "recordID": "..." }
Response: { "success": true, "anthropicUsage": {...} }

DELETE /auth/account

Request:  { "providerID": "anthropic", "recordID": "..." }
Response: { "success": true, "remaining": 2 }

3. Desktop App - Settings Menu

New DialogSettings component with tabs:

Tab Features
Providers Connected providers list, add new providers with search
Provider Detail Account list, usage bars, switch functionality, delete buttons
About GitHub, docs, Discord links, keyboard shortcuts

Delete Account Flow:

  1. Click X button on account
  2. Confirmation dialog appears
  3. Account removed from storage
  4. Auto-navigate back when last account removed

4. Desktop App - Context Panel Integration

When viewing a session using Anthropic:

  • Anthropic Rate Limits section appears after Context Breakdown
  • Shows 5-hour, 7-day (all), 7-day (sonnet) usage bars
  • Account switch buttons when multiple accounts configured
  • Matches existing Context Breakdown visual style

5. CLI Enhancements

Command Description
opencode auth list Shows providers with account counts
opencode auth usage Detailed usage per account with rate limits
opencode auth switch Interactive account switching
opencode auth logout Now supports selecting individual accounts

All provider lists are now sorted alphabetically.

Logout Account Selection:

$ opencode auth logout

┌  Remove credential
│
◆  Select provider
│  ● Anthropic (oauth)
│
◆  Remove which account?
│  ○ Remove all accounts (3 accounts)
│  ○ Account 1
│  ○ Account 2 
│  ● Account 3
│
◐  Account removed. 2 accounts remaining.
│
└  Done

Technical Implementation

Files Changed

File Changes
packages/opencode/src/auth/index.ts setActive(), removeRecord(), snapshot(), getAccounts(), fetchAnthropicUsage()
packages/opencode/src/auth/rotating-fetch.ts Prefer activeID in candidate selection
packages/opencode/src/server/server.ts POST /auth/active, DELETE /auth/account endpoints
packages/opencode/src/cli/cmd/auth.ts usage, switch commands, logout account selection, sorting
packages/app/src/components/dialog-settings.tsx New settings dialog with delete buttons
packages/app/src/components/session/session-context-tab.tsx Anthropic usage section
packages/app/src/pages/layout.tsx Settings button integration

Auto-Rotation Preserved

The automatic rotation on rate limit (429) is preserved:

if (response.status === 429) {
  await Auth.OAuthPool.recordOutcome({...cooldownUntil})
  await Auth.OAuthPool.moveToBack(providerID, namespace, nextID)
  continue // → Try next account
}

Current Limitations

  • Usage statistics: Only available for Anthropic (OAuth API limitation)
  • Multi-account support: Anthropic, OpenAI, GitHub Copilot (OAuth providers)
  • Other providers: Contributions welcome for usage stats

Testing

CLI

opencode auth list      # Should show account counts
opencode auth usage     # Should show per-account stats
opencode auth switch    # Should allow switching
opencode auth logout    # Should allow selecting individual accounts

Desktop

  1. Settings → Providers → Click connected provider
  2. Verify usage bars display correctly
  3. Switch accounts, verify bars update
  4. Click X on account → Confirm deletion
  5. Context panel → Verify Anthropic section appears

Related

Implementation

PR #9069 implements all features described above.

Metadata

Metadata

Assignees

Labels

webRelates to opencode on web / desktop

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions