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>
This commit is contained in:
153
scripts/fix-auth-profiles.sh
Executable file
153
scripts/fix-auth-profiles.sh
Executable file
@@ -0,0 +1,153 @@
|
||||
#!/bin/bash
|
||||
# fix-auth-profiles.sh — Fix broken Anthropic auth profiles in all OpenClaw agents
|
||||
#
|
||||
# Problem: Auth profiles may have {type:"oauth", key:"sk-ant-oat01-..."}
|
||||
# but OpenClaw's isValidProfile() for type:"oauth" checks for "access" field, not "key"
|
||||
# This causes the profile to be skipped and fall through to env var fallback
|
||||
#
|
||||
# Fix: Change "key" -> "access" field, clear cooldown stats
|
||||
#
|
||||
# Usage:
|
||||
# ./fix-auth-profiles.sh # auto-detect config dir
|
||||
# ./fix-auth-profiles.sh /path/to/.openclaw # custom config dir
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
OPENCLAW_CONFIG_DIR="${1:-}"
|
||||
LOG_PREFIX="[fix-auth-profiles]"
|
||||
|
||||
log() { echo "$LOG_PREFIX $*"; }
|
||||
error() { echo "$LOG_PREFIX ERROR: $*" >&2; }
|
||||
|
||||
# Auto-detect config dir if not provided
|
||||
if [ -z "$OPENCLAW_CONFIG_DIR" ]; then
|
||||
if [ -d "/root/.openclaw/agents" ]; then
|
||||
OPENCLAW_CONFIG_DIR="/root/.openclaw"
|
||||
elif [ -d "$HOME/.openclaw/agents" ]; then
|
||||
OPENCLAW_CONFIG_DIR="$HOME/.openclaw"
|
||||
else
|
||||
error "Cannot find OpenClaw config directory. Provide path as argument."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Config directory: $OPENCLAW_CONFIG_DIR"
|
||||
|
||||
AGENTS_DIR="$OPENCLAW_CONFIG_DIR/agents"
|
||||
if [ ! -d "$AGENTS_DIR" ]; then
|
||||
error "Agents directory not found: $AGENTS_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get current token from .env if available
|
||||
TOKEN=""
|
||||
for env_file in /root/openclaw/.env "$OPENCLAW_CONFIG_DIR/../openclaw/.env"; do
|
||||
if [ -f "$env_file" ]; then
|
||||
TOKEN=$(grep -oP 'ANTHROPIC_OAUTH_TOKEN="\K[^"]+' "$env_file" 2>/dev/null || true)
|
||||
[ -n "$TOKEN" ] && break
|
||||
fi
|
||||
done
|
||||
|
||||
FIXED=0
|
||||
SKIPPED=0
|
||||
|
||||
for agent_dir in "$AGENTS_DIR"/*/agent; do
|
||||
agent=$(basename "$(dirname "$agent_dir")")
|
||||
f="$agent_dir/auth-profiles.json"
|
||||
|
||||
if [ ! -f "$f" ]; then
|
||||
log "SKIP $agent: no auth-profiles.json"
|
||||
SKIPPED=$((SKIPPED + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
log "Checking $agent..."
|
||||
|
||||
python3 -c "
|
||||
import json, sys
|
||||
|
||||
with open('$f') as fh:
|
||||
data = json.load(fh)
|
||||
|
||||
changed = False
|
||||
|
||||
# Fix profile structure
|
||||
if 'anthropic:default' in data.get('profiles', {}):
|
||||
p = data['profiles']['anthropic:default']
|
||||
|
||||
# Ensure type is oauth
|
||||
if p.get('type') != 'oauth':
|
||||
p['type'] = 'oauth'
|
||||
changed = True
|
||||
|
||||
# Ensure provider is anthropic
|
||||
if p.get('provider') != 'anthropic':
|
||||
p['provider'] = 'anthropic'
|
||||
changed = True
|
||||
|
||||
# Move key -> access if needed
|
||||
if 'key' in p and 'access' not in p:
|
||||
p['access'] = p.pop('key')
|
||||
changed = True
|
||||
print(' Fixed: key -> access')
|
||||
elif 'key' in p and 'access' in p:
|
||||
del p['key']
|
||||
changed = True
|
||||
print(' Fixed: removed duplicate key field')
|
||||
|
||||
# Update token if provided
|
||||
token = '$TOKEN'
|
||||
if token and p.get('access') != token:
|
||||
p['access'] = token
|
||||
changed = True
|
||||
print(f' Updated token: {token[:20]}...')
|
||||
|
||||
if not changed:
|
||||
print(' Already correct')
|
||||
else:
|
||||
# Create the profile if it doesn't exist
|
||||
token = '$TOKEN'
|
||||
if token:
|
||||
if 'profiles' not in data:
|
||||
data['profiles'] = {}
|
||||
data['profiles']['anthropic:default'] = {
|
||||
'type': 'oauth',
|
||||
'provider': 'anthropic',
|
||||
'access': token
|
||||
}
|
||||
changed = True
|
||||
print(' Created anthropic:default profile')
|
||||
else:
|
||||
print(' No anthropic:default profile and no token to create one')
|
||||
sys.exit(0)
|
||||
|
||||
# Clear cooldown for anthropic profile
|
||||
if 'usageStats' in data and 'anthropic:default' in data['usageStats']:
|
||||
stats = data['usageStats']['anthropic:default']
|
||||
for key in ['cooldownUntil', 'errorCount', 'failureCounts', 'lastFailureAt']:
|
||||
if key in stats:
|
||||
del stats[key]
|
||||
changed = True
|
||||
if changed:
|
||||
print(' Cleared cooldown stats')
|
||||
|
||||
# Ensure lastGood points to anthropic:default
|
||||
if data.get('lastGood', {}).get('anthropic') != 'anthropic:default':
|
||||
if 'lastGood' not in data:
|
||||
data['lastGood'] = {}
|
||||
data['lastGood']['anthropic'] = 'anthropic:default'
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
with open('$f', 'w') as fh:
|
||||
json.dump(data, fh, indent=2)
|
||||
print(' Saved')
|
||||
"
|
||||
FIXED=$((FIXED + 1))
|
||||
done
|
||||
|
||||
log ""
|
||||
log "Done. Fixed: $FIXED agents, Skipped: $SKIPPED"
|
||||
log ""
|
||||
log "Restart gateway to apply changes:"
|
||||
log " cd /root/openclaw && docker compose down openclaw-gateway && docker compose up -d openclaw-gateway"
|
||||
Reference in New Issue
Block a user