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:
172
scripts/verify.sh
Executable file
172
scripts/verify.sh
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/bin/bash
|
||||
# verify.sh — Post-install health check for OAuth token sync
|
||||
# Run anytime to check if everything is working correctly
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
pass() { echo -e " ${GREEN}[PASS]${NC} $*"; }
|
||||
fail() { echo -e " ${RED}[FAIL]${NC} $*"; }
|
||||
warn() { echo -e " ${YELLOW}[WARN]${NC} $*"; }
|
||||
|
||||
ERRORS=0
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " OAuth Token Sync — Health Check"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# --- 1. Systemd service ---
|
||||
echo "1. Systemd service status"
|
||||
if systemctl is-active --quiet sync-oauth-token.service 2>/dev/null; then
|
||||
pass "sync-oauth-token.service is active"
|
||||
else
|
||||
fail "sync-oauth-token.service is not running"
|
||||
echo " Fix: systemctl start sync-oauth-token.service"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
|
||||
if systemctl is-enabled --quiet sync-oauth-token.service 2>/dev/null; then
|
||||
pass "Service is enabled (starts on boot)"
|
||||
else
|
||||
warn "Service is not enabled for boot"
|
||||
echo " Fix: systemctl enable sync-oauth-token.service"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 2. inotifywait process ---
|
||||
echo "2. File watcher process"
|
||||
if pgrep -f inotifywait > /dev/null 2>&1; then
|
||||
WATCH_PATH=$(pgrep -af inotifywait | grep -oP '/[^ ]+' | tail -1)
|
||||
pass "inotifywait is running (watching: $WATCH_PATH)"
|
||||
else
|
||||
fail "inotifywait is not running"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 3. Source credentials file ---
|
||||
echo "3. Claude CLI credentials file"
|
||||
# Try to find the watched file from the service
|
||||
SYNC_SCRIPT=$(which sync-oauth-token.sh 2>/dev/null || echo "/usr/local/bin/sync-oauth-token.sh")
|
||||
if [ -f "$SYNC_SCRIPT" ]; then
|
||||
SOURCE_FILE=$(grep 'CLAUDE_CREDS_FILE=' "$SYNC_SCRIPT" | head -1 | cut -d'"' -f2)
|
||||
fi
|
||||
SOURCE_FILE="${SOURCE_FILE:-/root/.openclaw/workspaces/workspace-claude-proxy/config/.claude/.credentials.json}"
|
||||
|
||||
if [ -f "$SOURCE_FILE" ]; then
|
||||
pass "File exists: $SOURCE_FILE"
|
||||
EXPIRES=$(python3 -c "
|
||||
import json, time
|
||||
with open('$SOURCE_FILE') as f:
|
||||
d = json.load(f)
|
||||
exp = d['claudeAiOauth']['expiresAt'] / 1000
|
||||
remaining = (exp - time.time()) / 3600
|
||||
status = 'VALID' if remaining > 0 else 'EXPIRED'
|
||||
print(f'{remaining:.1f}h remaining ({status})')
|
||||
" 2>/dev/null || echo "parse error")
|
||||
if echo "$EXPIRES" | grep -q "VALID"; then
|
||||
pass "Token: $EXPIRES"
|
||||
else
|
||||
fail "Token: $EXPIRES"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
else
|
||||
fail "File not found: $SOURCE_FILE"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 4. OpenClaw oauth.json ---
|
||||
echo "4. OpenClaw oauth.json"
|
||||
for path in /root/.openclaw/credentials/oauth.json /home/*/.openclaw/credentials/oauth.json; do
|
||||
if [ -f "$path" ]; then
|
||||
OAUTH_FILE="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "${OAUTH_FILE:-}" ] && [ -f "$OAUTH_FILE" ]; then
|
||||
HAS_ACCESS=$(python3 -c "
|
||||
import json
|
||||
with open('$OAUTH_FILE') as f:
|
||||
d = json.load(f)
|
||||
a = d.get('anthropic', {})
|
||||
print('yes' if a.get('access') else 'no')
|
||||
" 2>/dev/null || echo "no")
|
||||
if [ "$HAS_ACCESS" = "yes" ]; then
|
||||
pass "oauth.json exists with anthropic.access field: $OAUTH_FILE"
|
||||
else
|
||||
fail "oauth.json exists but missing anthropic.access field"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
else
|
||||
fail "oauth.json not found"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 5. .env file ---
|
||||
echo "5. Environment file (.env)"
|
||||
for path in /root/openclaw/.env; do
|
||||
if [ -f "$path" ]; then
|
||||
ENV_FILE="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "${ENV_FILE:-}" ] && [ -f "$ENV_FILE" ]; then
|
||||
if grep -q 'ANTHROPIC_OAUTH_TOKEN=' "$ENV_FILE"; then
|
||||
TOKEN_PREFIX=$(grep 'ANTHROPIC_OAUTH_TOKEN=' "$ENV_FILE" | head -1 | cut -d'"' -f2 | cut -c1-20)
|
||||
pass ".env has ANTHROPIC_OAUTH_TOKEN: ${TOKEN_PREFIX}..."
|
||||
else
|
||||
fail ".env missing ANTHROPIC_OAUTH_TOKEN"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
else
|
||||
fail ".env file not found"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 6. Gateway container ---
|
||||
echo "6. Gateway container"
|
||||
GATEWAY=$(docker ps --filter name=openclaw --format '{{.Names}}' 2>/dev/null | grep gateway | head -1)
|
||||
if [ -n "$GATEWAY" ]; then
|
||||
UPTIME=$(docker ps --filter "name=$GATEWAY" --format '{{.Status}}' 2>/dev/null)
|
||||
pass "Gateway running: $GATEWAY ($UPTIME)"
|
||||
|
||||
# Check container env var matches .env
|
||||
CONTAINER_TOKEN=$(docker exec "$GATEWAY" printenv ANTHROPIC_OAUTH_TOKEN 2>/dev/null | cut -c1-20)
|
||||
if [ -n "$CONTAINER_TOKEN" ]; then
|
||||
pass "Container has ANTHROPIC_OAUTH_TOKEN: ${CONTAINER_TOKEN}..."
|
||||
else
|
||||
warn "Container missing ANTHROPIC_OAUTH_TOKEN env var"
|
||||
fi
|
||||
else
|
||||
fail "No OpenClaw gateway container found"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- Summary ---
|
||||
echo "=========================================="
|
||||
if [ "$ERRORS" -eq 0 ]; then
|
||||
echo -e " ${GREEN}All checks passed${NC}"
|
||||
else
|
||||
echo -e " ${RED}$ERRORS check(s) failed${NC}"
|
||||
fi
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Useful commands:"
|
||||
echo " journalctl -u sync-oauth-token.service -f # Watch sync logs"
|
||||
echo " systemctl restart sync-oauth-token.service # Force re-sync"
|
||||
echo " ./scripts/verify.sh # Run this check again"
|
||||
echo ""
|
||||
|
||||
exit $ERRORS
|
||||
Reference in New Issue
Block a user