openclaw_oauth_sync/README.md
shamid202 22731fff60 Add complete OAuth token refresh and sync solution
- Setup wizard with auto-detection of OpenClaw paths and Claude CLI
- Token sync watcher (inotifywait) for real-time credential updates
- Auto-refresh trigger timer that runs Claude CLI every 30 min
- Supports Claude CLI in Docker container or on host
- Temporary ANTHROPIC_BASE_URL override for container environments
- Anthropic model configuration for OpenClaw
- Auth profile management (fixes key vs access field)
- Systemd services and timers for both sync and trigger
- Comprehensive documentation and troubleshooting guides
- Re-authentication notification system

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 01:51:18 +07:00

263 lines
8.9 KiB
Markdown

# OAuth Fix for OpenClaw + Claude Max
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:
1. **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.
2. **Token sync watcher** — An `inotifywait` service 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
```bash
git clone https://github.com/YOUR_USER/oauth-fix-openclaw-final.git
cd oauth-fix-openclaw-final
sudo ./setup.sh
```
The interactive wizard will:
1. Detect your OpenClaw installation paths
2. Find Claude CLI credentials
3. Configure the Anthropic model (if not already set up)
4. Install the token sync watcher (inotifywait)
5. Detect Claude CLI (container or host) and install the auto-refresh trigger
6. Test the CLI invocation to confirm it works
7. Verify everything works
## 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
- **python3**
- **inotify-tools** (optional, installed by wizard 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
1. `trigger-claude-refresh.sh` runs every 30 minutes, checks token expiry
2. If token has < 1.5 hours remaining, triggers Claude CLI
3. Claude CLI detects its token is near expiry
4. CLI calls Anthropic's refresh endpoint, gets new access token
5. CLI writes updated `.credentials.json`
6. `inotifywait` detects the file change (< 1 second)
7. `sync-oauth-token.sh` reads the new token
8. Maps fields: `accessToken` -> `access`, `refreshToken` -> `refresh`, `expiresAt` -> `expires`
9. Writes to `oauth.json` (OpenClaw's format)
10. Updates `ANTHROPIC_OAUTH_TOKEN` in `.env`
11. Recreates gateway container (`docker compose down/up` — NOT restart!)
12. 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**:
```bash
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_NEEDED` in 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):
```json
{
"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](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](docs/FIELD-MAPPING.md) for all formats.
## Manual Installation
If you prefer not to use the wizard:
### 1. Install inotify-tools
```bash
apt install inotify-tools
```
### 2. Edit and install the sync script
```bash
# 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
```bash
# 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
```bash
# 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](docs/OPENCLAW-MODEL-CONFIG.md).
## Verification
```bash
# 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
```bash
./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](docs/TROUBLESHOOTING.md) for common issues:
- Token expired errors
- `docker compose restart` not reloading env
- Auth profile `key` vs `access` field
- 404 from custom anthropic provider
- Cooldown errors
- Claude CLI not responding (ANTHROPIC_BASE_URL override)
- REAUTH_NEEDED flag (refresh token expired)
## Documentation
- [Architecture](docs/ARCHITECTURE.md) — Token flow, volume mounts, auth resolution
- [Troubleshooting](docs/TROUBLESHOOTING.md) — Common issues and fixes
- [Model Config](docs/OPENCLAW-MODEL-CONFIG.md) — Anthropic model setup in OpenClaw
- [Token Refresh](docs/HOW-TOKEN-REFRESH-WORKS.md) — How Claude CLI refreshes tokens
- [Field Mapping](docs/FIELD-MAPPING.md) — Credential format reference
## License
MIT