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:
112
scripts/trigger-claude-refresh.sh
Executable file
112
scripts/trigger-claude-refresh.sh
Executable file
@@ -0,0 +1,112 @@
|
||||
#!/bin/bash
|
||||
# trigger-claude-refresh.sh — Triggers Claude CLI to refresh OAuth token when near expiry
|
||||
#
|
||||
# Runs via systemd timer every 30 minutes.
|
||||
# Checks token expiry, triggers CLI only when needed.
|
||||
# The existing sync-oauth-token.sh (inotifywait) handles syncing to OpenClaw.
|
||||
#
|
||||
# Supports two modes:
|
||||
# Container mode: Claude CLI runs inside a Docker container
|
||||
# Host mode: Claude CLI is installed directly on the system
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
CREDS_FILE="@@CREDS_FILE@@"
|
||||
REAUTH_FLAG="@@REAUTH_FLAG@@"
|
||||
CLI_MODE="@@CLI_MODE@@"
|
||||
CLI_CONTAINER="@@CLI_CONTAINER@@"
|
||||
CLI_BASE_URL_OVERRIDE="@@CLI_BASE_URL_OVERRIDE@@"
|
||||
LOG_PREFIX="[trigger-refresh]"
|
||||
THRESHOLD_HOURS=1.5
|
||||
TIMEOUT_SECONDS=60
|
||||
|
||||
log() { echo "$LOG_PREFIX $*"; }
|
||||
log_err() { echo "$LOG_PREFIX ERROR: $*" >&2; }
|
||||
|
||||
# Check prerequisites
|
||||
if [ ! -f "$CREDS_FILE" ]; then
|
||||
log_err "Credentials file not found: $CREDS_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$CLI_MODE" = "container" ]; then
|
||||
if ! docker ps --filter "name=$CLI_CONTAINER" --format '{{.Names}}' | grep -q "$CLI_CONTAINER"; then
|
||||
log_err "Container $CLI_CONTAINER is not running"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! command -v claude &>/dev/null; then
|
||||
log_err "Claude CLI not found on system"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Read expiry and decide whether to trigger
|
||||
REMAINING=$(python3 -c "
|
||||
import json, time
|
||||
with open('$CREDS_FILE') as f:
|
||||
d = json.load(f)
|
||||
expires = d.get('claudeAiOauth', {}).get('expiresAt', 0)
|
||||
remaining = (expires / 1000 - time.time()) / 3600
|
||||
print(f'{remaining:.2f}')
|
||||
")
|
||||
|
||||
log "Token expires in ${REMAINING}h (threshold: ${THRESHOLD_HOURS}h)"
|
||||
|
||||
# Compare as integers (multiply by 100 to avoid bash float issues)
|
||||
REMAINING_X100=$(python3 -c "print(int(float('$REMAINING') * 100))")
|
||||
THRESHOLD_X100=$(python3 -c "print(int(float('$THRESHOLD_HOURS') * 100))")
|
||||
|
||||
if [ "$REMAINING_X100" -gt "$THRESHOLD_X100" ]; then
|
||||
log "Token still fresh, nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "Token near expiry, triggering Claude CLI refresh..."
|
||||
|
||||
# Record mtime BEFORE
|
||||
MTIME_BEFORE=$(stat -c %Y "$CREDS_FILE" 2>/dev/null || stat -f %m "$CREDS_FILE" 2>/dev/null)
|
||||
|
||||
# Trigger Claude CLI
|
||||
if [ "$CLI_MODE" = "container" ]; then
|
||||
if [ "$CLI_BASE_URL_OVERRIDE" = "true" ]; then
|
||||
CLI_OUTPUT=$(timeout "$TIMEOUT_SECONDS" docker exec \
|
||||
-e ANTHROPIC_BASE_URL=https://api.anthropic.com \
|
||||
"$CLI_CONTAINER" claude -p "say ok" --no-session-persistence 2>&1)
|
||||
else
|
||||
CLI_OUTPUT=$(timeout "$TIMEOUT_SECONDS" docker exec \
|
||||
"$CLI_CONTAINER" claude -p "say ok" --no-session-persistence 2>&1)
|
||||
fi
|
||||
else
|
||||
CLI_OUTPUT=$(timeout "$TIMEOUT_SECONDS" claude -p "say ok" --no-session-persistence 2>&1)
|
||||
fi
|
||||
CLI_EXIT=$?
|
||||
|
||||
if [ "$CLI_EXIT" -eq 124 ]; then
|
||||
log_err "CLI command timed out after ${TIMEOUT_SECONDS}s"
|
||||
fi
|
||||
|
||||
log "CLI exit code: $CLI_EXIT, output: $CLI_OUTPUT"
|
||||
|
||||
# Record mtime AFTER
|
||||
sleep 2
|
||||
MTIME_AFTER=$(stat -c %Y "$CREDS_FILE" 2>/dev/null || stat -f %m "$CREDS_FILE" 2>/dev/null)
|
||||
|
||||
if [ "$MTIME_BEFORE" != "$MTIME_AFTER" ]; then
|
||||
log "Token refreshed successfully (mtime changed: $MTIME_BEFORE -> $MTIME_AFTER)"
|
||||
|
||||
if [ -f "$REAUTH_FLAG" ]; then
|
||||
rm -f "$REAUTH_FLAG"
|
||||
log "Cleared previous REAUTH_NEEDED flag"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
else
|
||||
log_err "Token refresh FAILED — credentials.json was not updated"
|
||||
log_err "Re-authentication may be required (refresh token expired or subscription issue)"
|
||||
|
||||
echo "Re-authentication needed at $(date -u '+%Y-%m-%dT%H:%M:%SZ')" > "$REAUTH_FLAG"
|
||||
log_err "Wrote $REAUTH_FLAG"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user