Skip to content

wouter-intveld/opencode-claude-auth-sync

 
 

Repository files navigation

opencode-claude-auth-sync

Sync your existing Claude CLI credentials to OpenCode — no separate Anthropic login needed.

🔧 Getting 429 errors? The old built-in opencode-anthropic-auth@0.0.13 plugin may still be cached and interfering with token refresh. Remove it:

rm -rf ~/.cache/opencode/node_modules/opencode-anthropic-auth

If it keeps coming back, also remove opencode-anthropic-auth from ~/.cache/opencode/package.json. Then restart OpenCode and try again.

Why not an npm plugin? When auth breaks, npm packages pop up fast — but installing unknown packages that handle your OAuth tokens is a risk. This tool is a plain shell script you can read in full before running. No node_modules, no dependency tree, no trust required.

Quick Start

Linux / macOS / WSL

curl -fsSL https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/install.sh | bash

Windows (PowerShell as Administrator)

irm https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/install.ps1 | iex

Don't want a scheduler? Install without automatic syncing:

# Linux / macOS
curl -fsSL https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/install.sh | bash -s -- --no-scheduler

# Windows (PowerShell)
& { irm https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/install.ps1 -OutFile $env:TEMP\install.ps1; & $env:TEMP\install.ps1 --no-scheduler }

Then just run the sync manually whenever you need it:

claude-sync                                     # Linux / macOS (after install)
~/.local/bin/sync-claude-to-opencode.sh         # Linux / macOS direct path
claude-sync                                     # Windows (after install)
& "$HOME\.local\bin\sync-claude-to-opencode.ps1"  # Windows direct path

Verify

opencode providers list    # Should show: Anthropic  oauth
opencode models anthropic  # Should list Claude models (e.g. claude-opus-4-6)

Usage

# Normal sync (default, also runs via scheduler)
claude-sync

# Check token status without syncing
claude-sync --status

# Force refresh token via Claude CLI regardless of expiry
claude-sync --force

Multi-Account

Manage multiple Claude accounts with quota visibility, automatic rotation, and the shorter claude-sync command.

Important: Claude CLI itself only supports one logged-in account at a time. Multi-account here means this tool stores multiple credential sets in its own account store, then switches which one is written into OpenCode's auth.json.

Account store:

~/.config/opencode-claude-auth-sync/accounts.json

Add accounts

There are two ways to add an account.

Option A: already logged in via claude (recommended on SSH / remote machines)

If claude is already authenticated with the account you want to save, just capture the current session:

claude-sync --add personal
claude-sync --add work

Windows:

claude-sync --add personal
claude-sync --add work

This is the most reliable path on remote servers because Claude's login flow can be interactive.

Option B: login + save in one command

Use --login if you want the script to trigger Claude login and then save the result:

claude-sync --login personal
claude-sync --login work
claude-sync --login backup

Windows:

claude-sync --login personal
claude-sync --login work

Each --login logs out the current Claude session, starts Claude login, then saves the credentials under the given label.

If you're on SSH and --login feels awkward, use this flow instead:

claude
# run /login inside Claude if needed
exit

claude-sync --add work

Manage accounts

# List stored accounts
claude-sync --list

# Show active account status + current 5h / 7d usage
claude-sync --status

# Switch active account immediately
claude-sync --switch work

# Rotate to the next account (round-robin)
claude-sync --rotate

# Remove a stored account
claude-sync --remove backup

Example --status output:

Account: work (2 total)
Status:  valid (7h 56m remaining)
Expires: 2026-03-21T10:55:26.162Z
Plan:    max
Usage:   5h 2% (reset: 2026-03-21T07:00:00.152Z)
         7d 0% (reset: 2026-03-28T02:00:00.153Z)
         sonnet 3%

Rotation behavior

  • OpenCode still uses a single Anthropic entry in auth.json
  • This tool switches which stored account is written into that slot
  • If the active account is expired, the script first tries another non-expired stored account
  • If all stored accounts are expired, it falls back to Claude CLI refresh for the currently logged-in Claude account
  • 429 rate limits are not auto-detected yet; if one account is rate-limited, run claude-sync --rotate manually
  • --status shows the current account's 5h / 7d usage so you can decide when to rotate
  • The same Claude account can still be saved under two different labels if you add it twice

Store format

{
  "accounts": {
    "personal": {
      "accessToken": "...",
      "refreshToken": "...",
      "expiresAt": 1774027458398,
      "subscriptionType": "max",
      "rateLimitTier": "default_claude_max_20x",
      "addedAt": "2026-03-20T09:55:32.366Z"
    }
  },
  "active": "personal",
  "rotationIndex": 0
}

Platform Support

Platform Claude credentials Scheduler Install command
Linux / WSL ~/.claude/.credentials.json cron curl | bash
macOS macOS Keychain → file fallback LaunchAgent curl | bash
Windows (native) %USERPROFILE%\.claude\.credentials.json Task Scheduler PowerShell

Security

This tool is not an npm package — it's a plain shell script you can read before running.

  • No node_modules, no dependency tree, no supply chain risk
  • Single-file scripts: sync-claude-to-opencode.sh (bash) / .ps1 (PowerShell)
  • Credentials are passed via stdin, never exposed in process arguments
  • All JSON writes are atomic (temp file + rename) to prevent corruption
  • Review the source before installing: sync-claude-to-opencode.sh (~850 lines) / .ps1 (~620 lines)
# Inspect before running
curl -fsSL https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/sync-claude-to-opencode.sh | less

Prerequisites

  • OpenCode v1.2.27+
  • Claude CLI — authenticated (run claude at least once)
  • Node.js (bundled with OpenCode, or standalone)

Why?

OpenCode no longer provides built-in Anthropic login. If you want to use Claude models (Opus, Sonnet, Haiku, etc.) in OpenCode, you need to bring your own credentials.

This tool bridges the gap: it reads your existing Claude CLI OAuth tokens and writes them into OpenCode's auth store, letting an opencode-anthropic-auth plugin handle the rest (see v1.3+ compatibility).

How It Works

┌─────────────────────────┐      sync script      ┌─────────────────────────────┐
│  ~/.claude/              │  (launchd/cron/task)   │  ~/.local/share/opencode/   │
│  .credentials.json       │ ──────────────────▶   │  auth.json                  │
│                          │                       │                             │
│  claudeAiOauth {         │   reads & compares    │  anthropic {                │
│    accessToken,          │   ─────────────────▶  │    type: "oauth",           │
│    refreshToken,         │   writes if changed   │    access: <accessToken>,   │
│    expiresAt             │                       │    refresh: <refreshToken>, │
│  }                       │                       │    expires: <expiresAt>     │
│                          │                       │  }                         │
└─────────────────────────┘                       └─────────────────────────────┘
                                                             │
                                                             ▼
                                                    opencode-anthropic-auth plugin
                                                    handles token refresh,
                                                    request signing, OAuth beta
                                                    headers, and API routing.

Credential sources (platform-aware):

Platform Claude CLI stores credentials in How this script reads them
macOS macOS Keychain (service: Claude Code-credentials) security find-generic-password
Linux / WSL / Windows ~/.claude/.credentials.json Direct file read

Step by step:

  1. Claude CLI stores OAuth credentials after you run claude and authenticate (Keychain on macOS, file on Linux/Windows)
  2. This sync script detects the platform and reads the claudeAiOauth object from the appropriate source
  3. If the token is already expired, it automatically runs claude CLI to refresh the token before syncing
  4. It compares the accessToken, refreshToken, and expiresAt with what's currently in OpenCode's auth.json
  5. If they differ (or the Anthropic entry doesn't exist), it writes the new credentials
  6. If they're identical, it logs the remaining token lifetime and exits (no unnecessary writes)
  7. Once the credentials are in auth.json, the opencode-anthropic-auth plugin handles everything else: token refresh, request signing, OAuth beta headers, and user-agent

Claude CLI tokens are valid for approximately 5–6 hours. The sync job runs every 15 minutes (LaunchAgent on macOS, cron on Linux, Task Scheduler on Windows). Once a token has expired, the script uses Claude CLI to refresh it and then re-syncs auth.json. On macOS, LaunchAgent catches up on missed runs after sleep/wake.

Install (detailed)

Automatic (with AI agent)

Paste this to your AI coding agent (Claude Code, OpenCode, Cursor, etc.):

Install opencode-claude-auth-sync from https://github.com/lehdqlsl/opencode-claude-auth-sync

1. Run the install script:
   # Linux / macOS
   curl -fsSL https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/install.sh | bash

   # Windows (PowerShell as Admin)
   irm https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/install.ps1 | iex

2. Check the sync output. If it says "EXPIRED", the stored token is stale.
   The script will try to refresh it automatically via Claude CLI. If that still fails, run `claude` manually, then re-run the sync:
   # Linux / macOS
   claude-sync
   # Windows
   claude-sync

3. Verify — the output should show remaining time, not EXPIRED:
   opencode providers list    # Should show: Anthropic oauth
   opencode models anthropic  # Should list Claude models

4. If you see "Token refresh failed: 429", that means expired tokens were used.
   Re-authenticate with `claude` first, then sync again.

5. If already installed and just need to refresh tokens (no reinstall needed):
   Run `claude` to re-authenticate, then sync:
   # Linux / macOS
   claude-sync
   # Windows
   claude-sync

6. If the user doesn't want a background scheduler, install with --no-scheduler:
   # Linux / macOS
   curl -fsSL https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/install.sh | bash -s -- --no-scheduler
   # Windows
   Download and run install.ps1 with --no-scheduler flag
   Then sync manually whenever needed.

Linux / macOS (manual)

mkdir -p ~/.local/bin
curl -fsSL https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/sync-claude-to-opencode.sh \
  -o ~/.local/bin/sync-claude-to-opencode.sh
chmod +x ~/.local/bin/sync-claude-to-opencode.sh
ln -sf ~/.local/bin/sync-claude-to-opencode.sh ~/.local/bin/claude-sync

claude-sync

(Optional) Set up automatic syncing (every 15 minutes):

# macOS — LaunchAgent (recommended, catches up after sleep)
# Use the install script: curl ... | bash

# Linux — cron
(crontab -l 2>/dev/null; echo "*/15 * * * * \$HOME/.local/bin/sync-claude-to-opencode.sh >> \$HOME/.local/share/opencode/sync-claude.log 2>&1") | crontab -

Windows (manual)

New-Item -ItemType Directory -Force -Path "$HOME\.local\bin" | Out-Null
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/sync-claude-to-opencode.ps1" `
  -OutFile "$HOME\.local\bin\sync-claude-to-opencode.ps1"

@"
@echo off
setlocal
powershell.exe -ExecutionPolicy Bypass -File "%~dp0sync-claude-to-opencode.ps1" %*
"@ | Set-Content -Path "$HOME\.local\bin\claude-sync.cmd"

claude-sync

Configuration

Environment Variable Default Description
CLAUDE_CREDENTIALS_PATH ~/.claude/.credentials.json (Linux/Win) or Keychain (macOS) Path to Claude CLI credentials
OPENCODE_AUTH_PATH ~/.local/share/opencode/auth.json Path to OpenCode auth store

Uninstall

Linux / macOS

curl -fsSL https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/uninstall.sh | bash

Windows (PowerShell as Administrator)

irm https://raw.githubusercontent.com/lehdqlsl/opencode-claude-auth-sync/main/uninstall.ps1 | iex

Known Issues

Using alongside opencode-claude-auth npm plugin

If you're using opencode-claude-auth (v0.5+), you don't need this tool — that plugin syncs credentials in-process. Choose one or the other, not both.

Early versions (v0.2.x) had issues that have since been fixed. If you're on an old version, update or remove it.

Token expiration / "EXPIRED" status

The sync script attempts an automatic refresh via Claude CLI once the token is expired. If Claude CLI can refresh successfully, the next sync writes fresh credentials back to OpenCode.

Note: If the token expired while OpenCode was running, you may need to restart OpenCode after the sync to pick up the new credentials. This is rare — normally Claude CLI refreshes tokens before they expire, so OpenCode reads them seamlessly.

If auto-refresh fails (e.g. claude CLI not in PATH, or network issues):

  1. Re-authenticate manually:
    claude
  2. Re-run the sync:
    # Linux / macOS
    claude-sync
    
    # Windows
    claude-sync

Token refresh failed: 429

This means OpenCode tried to use an expired token. The sync script's auto-refresh should prevent this, but if it occurs, re-authenticate with claude and sync again.

If the deprecated built-in plugin keeps being reinstalled, remove both:

rm -rf ~/.cache/opencode/node_modules/opencode-anthropic-auth

and the opencode-anthropic-auth dependency entry from ~/.cache/opencode/package.json, then restart OpenCode.

If you're on OpenCode v1.2.27 and the deprecated plugin keeps coming back on every startup, that's an upstream built-in plugin issue. A practical CLI-side workaround is:

  1. Start OpenCode with OPENCODE_DISABLE_DEFAULT_PLUGINS=true
  2. Explicitly register opencode-claude-auth@latest in opencode.json

Example:

{
  "plugin": [
    "opencode-claude-auth@latest"
  ]
}

This disables the old built-in plugin injection while still loading a Claude auth provider explicitly.

Sync log

Check the sync history:

cat ~/.local/share/opencode/sync-claude.log

OpenCode v1.3+ compatibility

OpenCode v1.3 removes the built-in opencode-anthropic-auth plugin (PR #18186) per Anthropic's legal request. This tool depends on that plugin to handle token refresh and request signing.

You need to register an auth plugin manually in your opencode.json. Pick one:

Plugin Install Notes
@ex-machina/opencode-anthropic-auth npm i -g @ex-machina/opencode-anthropic-auth TypeScript rewrite, fixes 429 bug
op-anthropic-auth npm i -g op-anthropic-auth Fork of the original
opencode-anthropic-auth@0.0.13 npm i -g opencode-anthropic-auth@0.0.13 Original (deprecated)

Then add to opencode.json:

{
  "plugin": ["@ex-machina/opencode-anthropic-auth"]
}

If the npm packages get unpublished, this repo includes a bundled copy of the original plugin (opencode-anthropic-auth-0.0.13.tgz). Extract it and reference the local file:

{
  "plugin": ["/path/to/index.mjs"]
}

This tool (opencode-claude-auth-sync) itself only copies credentials and has no legal concerns. The compatibility risk is with the auth plugin that actually uses them.

License

MIT

About

Sync Claude CLI credentials to OpenCode — no separate Anthropic login needed

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Shell 56.5%
  • PowerShell 43.5%