Skip to content

feat: Auto-Relogin for Anthropic OAuth via Persistent Browser Sessions #9360

@mguttmann

Description

@mguttmann

Problem

OAuth tokens expire after ~12 hours of inactivity, causing "Token refresh failed: 400" errors when users return to OpenCode. This is a widespread issue affecting many users:

Current workaround: Users must manually re-login every morning, which disrupts workflow.

Root cause: Anthropic's OAuth refresh tokens become invalid after extended inactivity periods. This cannot be prevented by periodic token refresh or API pings - the session itself expires server-side.

Proposed Solution

Implement persistent headless browser sessions that can automatically refresh OAuth tokens when 400 errors occur.

How it works

  1. One-time setup: User runs opencode auth browser setup, browser opens, user logs into claude.ai
  2. Session persists: Browser profile saved to ~/.opencode/browsers/anthropic/<account-id>/
  3. Auto-refresh: When a 400 error occurs:
    • Headless browser launches with saved profile (already logged in)
    • Navigates to OAuth authorize URL
    • Automatically redirected to callback (no user interaction needed)
    • New tokens extracted and saved
    • Original request retried

Architecture

┌─────────────────┐     ┌──────────────┐     ┌─────────────────────┐
│ OpenCode        │────▶│ Auth Module  │────▶│ Headless Browser    │
│ (API Call)      │     │ (Error 400)  │     │ (Playwright)        │
└─────────────────┘     └──────────────┘     └─────────────────────┘
                               │                       │
                               ▼                       ▼
                        ┌──────────────┐     ┌─────────────────────┐
                        │ Retry with   │◀────│ New OAuth Token     │
                        │ new Token    │     │ (auto-extracted)    │
                        └──────────────┘     └─────────────────────┘

Features

Multi-Account Support

Each OAuth account gets its own browser profile, enabling auto-relogin for all accounts:

~/.opencode/browsers/anthropic/
  ├── <account-1-id>/    # Browser profile for Account 1
  ├── <account-2-id>/    # Browser profile for Account 2
  └── <account-n-id>/    # Browser profile for Account N

CLI Commands

# Setup browser session for an account
$ opencode auth browser setup
◆ Select account to configure:
│ ○ account-1@email.com
│ ● account-2@email.com
│
◐ Opening browser... Please log in to claude.ai
◐ Login detected. Saving session...
└ Browser session configured for account-2@email.com

# Check status of all browser sessions
$ opencode auth browser status
Account 1 (account-1@email.com): ● Active (last refresh: 2h ago)
Account 2 (account-2@email.com): ○ Not configured
Account 3 (account-3@email.com): ● Active (last refresh: 5min ago)

# Remove a browser session
$ opencode auth browser remove
◆ Select account to remove session:
│ ● account-1@email.com
│
└ Browser session removed

Desktop UI Integration

In Settings → Providers → Anthropic → [Account]:

┌─────────────────────────────────────────────────┐
│ Account: account@email.com                      │
├─────────────────────────────────────────────────┤
│ Usage: ████████░░ 80%                           │
│                                                 │
│ ─────────────────────────────────────────────── │
│                                                 │
│ 🔄 Auto-Relogin                                 │
│                                                 │
│ Status: ● Enabled                               │
│ Last Refresh: 2 hours ago                       │
│                                                 │
│ [Configure Session]  [Remove Session]           │
│                                                 │
├─────────────────────────────────────────────────┤
│ [Switch to this Account]  [Delete Account]      │
└─────────────────────────────────────────────────┘

Technical Implementation

New Files

File Purpose
packages/opencode/src/auth/browser.ts Headless browser session management
packages/opencode/src/auth/auto-relogin.ts Error detection & auto-refresh logic

Modified Files

File Changes
packages/opencode/src/auth/index.ts Add browserSession field to OAuthRecord
packages/opencode/src/cli/cmd/auth.ts Add browser subcommands
packages/app/src/components/dialog-settings.tsx Add Auto-Relogin UI section
packages/opencode/package.json Add Playwright dependency

Auth Store Schema Extension

const OAuthRecord = z.object({
  // ... existing fields ...
  browserSession: z.object({
    enabled: z.boolean(),
    profilePath: z.string(),
    lastRefresh: z.number().optional(),
    lastError: z.string().optional(),
  }).optional(),
})

API Endpoints

Endpoint Purpose
POST /auth/browser/setup Initiate browser session setup
GET /auth/browser/status Get browser session status for all accounts
DELETE /auth/browser/:recordId Remove browser session for account

Dependencies

Security Considerations

  • Browser profiles stored locally in user's data directory
  • No credentials transmitted over network (browser handles auth natively)
  • Sessions can be removed at any time via CLI or UI
  • Headless browser runs only when needed (not persistent daemon)

Acceptance Criteria

  • opencode auth browser setup opens browser for login
  • Browser session persists after setup
  • 400 errors trigger automatic token refresh
  • Multi-account: each account has separate session
  • CLI shows browser session status
  • Desktop UI shows status and config options
  • Sessions can be removed via CLI and UI
  • Works on macOS, Linux, Windows

Related Issues

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions