OpenClaw + Claude Max: Auto-Renewing Anthropic OAuth Tokens So Your Agents Never Go Silent
The Tweet That Started This
This morning someone posted exactly what half the OpenClaw community has been silently suffering through:
> *"This morning I woke up to all 6 of my AI Agents running perfectly — for the first time without me touching anything. That's new. I run OpenClaw with Claude Max on Mac Mini, and Anthropic's OAuth access tokens expire every 8 hours. When they do, every agent goes silent."*
If you run OpenClaw with Claude Max (Anthropic's subscription plan), you're not using an API key — you're using an OAuth session that Anthropic issues through their web login flow. Unlike an API key that never expires, these OAuth access tokens have a hard 8-hour TTL.
Every 8 hours: silence. Every morning: manual fix. That's the default experience unless you solve it.
This post covers exactly how to automate the renewal so you never touch it again.
---
Why This Happens: OAuth vs. API Key
When you connect OpenClaw to Anthropic via Claude Max (not the API tier), the auth flow works like this:
1. You log in via browser — Anthropic issues an access token (short-lived, ~8h) and a refresh token (long-lived)
2. OpenClaw uses the access token for every request
3. After 8 hours the access token expires — requests start returning 401
4. OpenClaw marks the account as unauthenticated — agents stop responding
The refresh token can get a new access token without re-logging in. The problem is that, by default, nothing in your setup is calling that refresh endpoint automatically.
---
Step 1: Find Your Tokens
OpenClaw stores auth credentials here:
```bash
cat ~/.openclaw/config.json | grep -A 10 '"anthropic"'
```
You're looking for a structure like:
```json
{
"anthropic": {
"authType": "oauth",
"accessToken": "sk-ant-oaXXX...",
"refreshToken": "rt-XXXXX...",
"expiresAt": 1743091200000
}
}
```
The `refreshToken` is what you need. It's long-lived (typically 30-90 days) and can be used to get new access tokens without user interaction.
---
Step 2: The Refresh Script
Create this script at `~/scripts/refresh-anthropic-token.sh`:
```bash
#!/bin/bash
set -e
CONFIG="$HOME/.openclaw/config.json"
BACKUP="$HOME/.openclaw/config.json.bak"
# Read current refresh token
REFRESH_TOKEN=$(cat "$CONFIG" | python3 -c "
import json, sys
cfg = json.load(sys.stdin)
print(cfg.get('anthropic', {}).get('refreshToken', ''))
")
if [ -z "$REFRESH_TOKEN" ]; then
echo "ERROR: No refresh token found in config.json"
exit 1
fi
# Call Anthropic's token endpoint
RESPONSE=$(curl -s -X POST "https://console.anthropic.com/v1/oauth/token" \
-H "Content-Type: application/json" \
-d "{
\"grant_type\": \"refresh_token\",
\"refresh_token\": \"$REFRESH_TOKEN\"
}")
NEW_ACCESS_TOKEN=$(echo "$RESPONSE" | python3 -c "
import json, sys
data = json.load(sys.stdin)
if 'access_token' not in data:
print('ERROR: ' + str(data), file=sys.stderr)
sys.exit(1)
print(data['access_token'])
")
NEW_EXPIRES=$(echo "$RESPONSE" | python3 -c "
import json, sys, time
data = json.load(sys.stdin)
expires_in = data.get('expires_in', 28800) # default 8h
print(int((time.time() + expires_in) * 1000))
")
# Back up config and update
cp "$CONFIG" "$BACKUP"
python3 -c "
import json, sys
with open('$CONFIG') as f:
cfg = json.load(f)
cfg['anthropic']['accessToken'] = '$NEW_ACCESS_TOKEN'
cfg['anthropic']['expiresAt'] = $NEW_EXPIRES
with open('$CONFIG', 'w') as f:
json.dump(cfg, f, indent=2)
print('Token updated. Expires at:', $NEW_EXPIRES)
"
# Reload OpenClaw gateway so it picks up new token
openclaw gateway restart --quiet 2>/dev/null || true
echo "Done. New token active."
```
Make it executable:
```bash
chmod +x ~/scripts/refresh-anthropic-token.sh
```
---
Step 3: Test It
Run manually once to confirm it works:
```bash
~/scripts/refresh-anthropic-token.sh
```
You should see:
```
Token updated. Expires at: 1743120000000
Done. New token active.
```
Then verify your agents are still responding by sending a message in your configured channel.
---
Step 4: Automate with Cron
You want to refresh every 6 hours — safely before the 8-hour expiry, with a 2-hour buffer.
Add to crontab:
```bash
crontab -e
```
```cron
0 */6 * * * /bin/bash $HOME/scripts/refresh-anthropic-token.sh >> $HOME/.openclaw/logs/token-refresh.log 2>&1
```
Or if you prefer OpenClaw's built-in cron system (recommended — uses the same scheduler your agents use):
In your OpenClaw config:
```json
{
"cron": {
"jobs": [
{
"name": "Anthropic Token Refresh",
"schedule": { "kind": "every", "everyMs": 21600000 },
"payload": {
"kind": "systemEvent",
"text": "Run shell: bash $HOME/scripts/refresh-anthropic-token.sh"
}
}
]
}
}
```
Or use the OpenClaw cron CLI:
```bash
openclaw cron add \
--name "Anthropic Token Refresh" \
--every 6h \
--cmd "bash $HOME/scripts/refresh-anthropic-token.sh"
```
---
Step 5: Add a Health Check
The script above is silent when it works — but you want to know when it *fails*. Add a notification:
```bash
# At the top of the script, wrap everything in error handling:
trap 'echo "TOKEN REFRESH FAILED at $(date)" | openclaw notify --channel telegram' ERR
```
Or use the OpenClaw watchdog — if your agent doesn't respond to a heartbeat after token refresh, it triggers an alert automatically.
---
Alternative: Use the API Tier Instead
If this feels like too much plumbing, the cleanest solution is switching from Claude Max (subscription) to the Anthropic API (pay-per-token):
| | Claude Max | Anthropic API |
|---|---|---|
| Auth | OAuth (8h TTL) | API key (no expiry) |
| Cost | Flat monthly fee | Pay-per-token |
| Best for | Heavy personal use | Predictable workloads |
| Token management | Manual or scripted | None needed |
For most OpenClaw setups with 3-6 agents running 24/7, the API tier ends up cheaper than Claude Max anyway — especially with `claude-haiku-3-5` for routine tasks and `claude-sonnet` only for complex ones.
---
Debugging: When the Refresh Fails
401 on the refresh endpoint:
Your refresh token itself may have expired. You'll need to re-authenticate manually: `openclaw auth login --provider anthropic`. This should give you a new refresh token with a fresh TTL.
Config update succeeds but agents still 401:
The gateway didn't pick up the new token. Force a restart: `openclaw gateway restart`.
Refresh token not in config.json:
Older OpenClaw versions store tokens differently. Check: `~/.openclaw/auth/` — there may be per-provider token files there instead.
curl: command not found in cron:
Cron runs with a minimal PATH. Either use full path (`/usr/bin/curl`) or source your profile at the top of the script: `source $HOME/.profile`.
---
The OpenClaw-Native Approach
If you're on OpenClaw 0.9+, there's a cleaner path: the gateway has a built-in auth refresh hook. You can configure it directly:
```json
{
"providers": {
"anthropic": {
"authType": "oauth",
"autoRefresh": true,
"refreshIntervalMs": 21600000
}
}
}
```
When `autoRefresh: true`, the gateway handles token rotation internally — no script, no cron job. This is the recommended approach for 0.9+. Check your version: `openclaw --version`.
If you're on an older version, the script approach above is the reliable fallback.
---
Summary
| Problem | Anthropic OAuth tokens expire every 8 hours |
|---|---|
| Symptom | All agents go silent overnight |
| Fix (scripted) | refresh-anthropic-token.sh + cron every 6h |
| Fix (native) | `autoRefresh: true` in config (OpenClaw 0.9+) |
| Nuclear option | Switch to Anthropic API tier (API keys don't expire) |
The first time this hits you at 3 AM — all 6 agents dead, client messages piling up — you fix it in 20 minutes and never think about it again. That's what this post is for.
The full configuration, all scripts, and monitoring setup are in the OpenClaw Setup Playbook.
Auch auf Deutsch verfügbar. 🇩🇪
Want to learn more?
Our playbook contains 18 detailed chapters — available in English and German.
Get the Playbook