- Add ROOH credit (www.rooh.red) to banner, summary, and README - Step 1: Offer to install python3 and curl instead of hard-failing - Step 3: Detect missing Claude CLI and offer to install via npm - Step 3: Detect not-signed-in CLI and offer interactive OAuth sign-in - Step 3: Provide clear instructions and exit paths at every decision point - Update README with correct git clone URL and wizard capabilities - All install steps now require user confirmation before proceeding Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9.4 KiB
OAuth Fix for OpenClaw + Claude Max
Created by ROOH — www.rooh.red
Automatic Anthropic OAuth token refresh for OpenClaw. Keeps your Claude Max tokens alive indefinitely.
The Problem
OpenClaw uses Anthropic Claude models (e.g., claude-opus-4-6) via OAuth tokens from Claude Max subscriptions. These tokens expire every ~8 hours. Without automated refresh, all agents stop working with:
HTTP 401 authentication_error: OAuth token has expired
The Solution
Two services working together:
- Auto-refresh trigger — A timer that runs Claude CLI every 30 minutes to check and refresh the token before it expires. Supports Claude CLI in a Docker container or installed on the host.
- Token sync watcher — An
inotifywaitservice that detects when Claude CLI writes new credentials and instantly syncs them to OpenClaw.
Timer (every 30min) Claude Code CLI sync-oauth-token.sh OpenClaw Gateway
(triggers CLI when ---> (refreshes token, ---> (watches for changes, ---> (gets fresh token)
token near expiry) writes creds file) syncs via inotifywait)
Quick Start
git clone https://git.eeqj.de/ROOH/openclaw_oauth_sync.git
cd openclaw_oauth_sync
sudo ./setup.sh
The interactive wizard will:
- Check prerequisites (offers to install python3, curl, inotify-tools if missing)
- Detect your OpenClaw installation paths
- Find Claude CLI credentials (offers to install CLI and help with sign-in if needed)
- Configure the Anthropic model (if not already set up)
- Install the token sync watcher (inotifywait or timer fallback)
- Detect Claude CLI (container or host) and install the auto-refresh trigger
- Test the CLI invocation to confirm it works
- Verify everything works
Every install step asks for your confirmation first — you have full control over what gets installed.
Prerequisites
- Linux server with systemd
- Docker + Docker Compose v2
- OpenClaw installed and running
- Claude Max subscription with OAuth credentials
- Claude Code CLI — either in a Docker container or installed on the host (wizard can install it)
- python3 (wizard offers to install if missing)
- curl (wizard offers to install if missing)
- inotify-tools (optional, wizard offers to install if missing)
How It Works
Architecture
+---------------------------+
| trigger-claude-refresh.sh | (systemd timer, every 30 min)
| checks token expiry |
| if < 1.5h remaining: |
| triggers Claude CLI |
+-------------+-------------+
|
v
+--------------------+ auto-refresh +-------------------+
| Claude Code CLI | =================> | .credentials.json |
| (container or host)| (token near expiry) +--------+----------+
+--------------------+ |
inotifywait detects change
|
+----------v----------+
| sync-oauth-token.sh |
+--+------+------+----+
| | |
oauth.json .env gateway
(mapped (env restart
fields) var) (down/up)
Token Flow
trigger-claude-refresh.shruns every 30 minutes, checks token expiry- If token has < 1.5 hours remaining, triggers Claude CLI
- Claude CLI detects its token is near expiry
- CLI calls Anthropic's refresh endpoint, gets new access token
- CLI writes updated
.credentials.json inotifywaitdetects the file change (< 1 second)sync-oauth-token.shreads the new token- Maps fields:
accessToken->access,refreshToken->refresh,expiresAt->expires - Writes to
oauth.json(OpenClaw's format) - Updates
ANTHROPIC_OAUTH_TOKENin.env - Recreates gateway container (
docker compose down/up— NOT restart!) - Gateway starts with the fresh token
ANTHROPIC_BASE_URL Override
If Claude CLI runs in a container with ANTHROPIC_BASE_URL set to a proxy (e.g., LiteLLM), the trigger script uses a temporary per-invocation override:
docker exec -e ANTHROPIC_BASE_URL=https://api.anthropic.com container claude -p "say ok"
The -e flag overrides the env var only for that single command. The container's running processes are unaffected. This is detected and configured automatically by the wizard.
Re-authentication Notification
If the refresh token itself expires (e.g., subscription lapsed), the trigger script:
- Creates a flag file at
REAUTH_NEEDEDin the OpenClaw directory - Logs an error to journalctl
- Future: Mattermost webhook notification
Why down/up and NOT restart?
docker compose restart does NOT reload .env variables. It restarts the same container with the same environment. Only docker compose down + docker compose up -d creates a new container that reads .env fresh.
Anthropic Model Configuration
OpenClaw has a built-in Anthropic provider. Do NOT add anthropic to models.providers in openclaw.json — it causes double /v1 in URLs resulting in 404 errors.
The correct configuration (set by the wizard):
{
"agents": {
"defaults": {
"model": {
"primary": "anthropic/claude-opus-4-6"
},
"models": {
"anthropic/claude-opus-4-6": { "alias": "Claude Opus 4.6 (Max)" },
"anthropic/claude-sonnet-4-6": { "alias": "Claude Sonnet 4.6 (Max)" }
}
}
}
}
See docs/OPENCLAW-MODEL-CONFIG.md for full details.
Credential Field Mapping
Claude CLI and OpenClaw use different field names:
Claude CLI (.credentials.json) |
OpenClaw (oauth.json) |
|---|---|
claudeAiOauth.accessToken |
anthropic.access |
claudeAiOauth.refreshToken |
anthropic.refresh |
claudeAiOauth.expiresAt |
anthropic.expires |
See docs/FIELD-MAPPING.md for all formats.
Manual Installation
If you prefer not to use the wizard:
1. Install inotify-tools
apt install inotify-tools
2. Edit and install the sync script
# Edit scripts/sync-oauth-token.sh — replace @@PLACEHOLDER@@ values:
# @@CLAUDE_CREDS_FILE@@ = path to Claude CLI .credentials.json
# @@OPENCLAW_OAUTH_FILE@@ = path to OpenClaw oauth.json
# @@OPENCLAW_ENV_FILE@@ = path to OpenClaw .env
# @@COMPOSE_DIR@@ = path to OpenClaw docker-compose directory
cp scripts/sync-oauth-token.sh /usr/local/bin/
chmod +x /usr/local/bin/sync-oauth-token.sh
3. Install systemd service
# Edit templates/sync-oauth-token.service — replace @@SYNC_SCRIPT_PATH@@
cp templates/sync-oauth-token.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now sync-oauth-token.service
4. Install the auto-refresh trigger
# Edit scripts/trigger-claude-refresh.sh — replace @@PLACEHOLDER@@ values:
# @@CREDS_FILE@@ = path to Claude CLI .credentials.json
# @@REAUTH_FLAG@@ = path to REAUTH_NEEDED flag file
# @@CLI_MODE@@ = "container" or "host"
# @@CLI_CONTAINER@@ = container name (if container mode)
# @@CLI_BASE_URL_OVERRIDE@@ = "true" or "false"
cp scripts/trigger-claude-refresh.sh /usr/local/bin/
chmod +x /usr/local/bin/trigger-claude-refresh.sh
# Edit templates/trigger-claude-refresh.service — replace @@TRIGGER_SCRIPT_PATH@@
cp templates/trigger-claude-refresh.service /etc/systemd/system/
cp templates/trigger-claude-refresh.timer /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now trigger-claude-refresh.timer
5. Configure OpenClaw
See docs/OPENCLAW-MODEL-CONFIG.md.
Verification
# Run the health check
./scripts/verify.sh
# Watch sync logs in real-time
journalctl -u sync-oauth-token.service -f
# Check trigger logs
journalctl -u trigger-claude-refresh -n 20
# Check all timers
systemctl list-timers sync-oauth-token* trigger-claude-refresh*
# Check service status
systemctl status sync-oauth-token.service
systemctl status trigger-claude-refresh.timer
Uninstall
./setup.sh --uninstall
# or
./scripts/uninstall.sh
Fallback Method (Timer)
If inotifywait is unavailable, the wizard installs a systemd timer that refreshes the token directly via Anthropic's API every 6 hours. This is less responsive but doesn't require inotify.
Troubleshooting
See docs/TROUBLESHOOTING.md for common issues:
- Token expired errors
docker compose restartnot reloading env- Auth profile
keyvsaccessfield - 404 from custom anthropic provider
- Cooldown errors
- Claude CLI not responding (ANTHROPIC_BASE_URL override)
- REAUTH_NEEDED flag (refresh token expired)
Documentation
- Architecture — Token flow, volume mounts, auth resolution
- Troubleshooting — Common issues and fixes
- Model Config — Anthropic model setup in OpenClaw
- Token Refresh — How Claude CLI refreshes tokens
- Field Mapping — Credential format reference
Author
ROOH — www.rooh.red
License
MIT