2026-01-09 09:12:19 +10:30
#!/bin/bash
# Claude Code Authentication Status Checker
2026-01-30 03:15:10 +01:00
# Checks both Claude Code and OpenClaw auth status
2026-01-09 09:12:19 +10:30
set -euo pipefail
CLAUDE_CREDS = " $HOME /.claude/.credentials.json "
2026-01-30 03:15:10 +01:00
OPENCLAW_AUTH = " $HOME /.openclaw/agents/main/agent/auth-profiles.json "
2026-01-09 09:12:19 +10:30
# Colors for terminal output
RED = '\033[0;31m'
YELLOW = '\033[1;33m'
GREEN = '\033[0;32m'
NC = '\033[0m' # No Color
# Output mode: "full" (default), "json", or "simple"
OUTPUT_MODE = " ${ 1 :- full } "
2026-01-09 00:32:48 +00:00
fetch_models_status_json( ) {
2026-01-30 03:15:10 +01:00
openclaw models status --json 2>/dev/null || true
2026-01-09 00:32:48 +00:00
}
2026-01-09 09:12:19 +10:30
2026-01-09 00:32:48 +00:00
STATUS_JSON = " $( fetch_models_status_json) "
USE_JSON = 0
if [ -n " $STATUS_JSON " ] ; then
USE_JSON = 1
fi
calc_status_from_expires( ) {
local expires_at = " $1 "
if ! [ [ " $expires_at " = ~ ^-?[ 0-9] +$ ] ] ; then
expires_at = 0
fi
local now_ms = $(( $( date +%s) * 1000 ))
2026-01-09 09:12:19 +10:30
local diff_ms = $(( expires_at - now_ms))
local hours = $(( diff_ms / 3600000 ))
local mins = $(( ( diff_ms % 3600000 ) / 60000 ))
2026-01-09 00:32:48 +00:00
if [ " $expires_at " -le 0 ] ; then
echo "MISSING"
return 1
elif [ " $diff_ms " -lt 0 ] ; then
2026-01-09 09:12:19 +10:30
echo "EXPIRED"
return 1
elif [ " $diff_ms " -lt 3600000 ] ; then
echo " EXPIRING: ${ mins } m "
return 2
else
echo " OK: ${ hours } h ${ mins } m "
return 0
fi
}
2026-01-09 00:32:48 +00:00
json_expires_for_claude_cli( ) {
echo " $STATUS_JSON " | jq -r '
[ .auth.oauth.profiles[ ]
2026-01-26 19:04:49 +00:00
| select ( .provider = = "anthropic" and ( .type = = "oauth" or .type = = "token" ) )
2026-01-09 00:32:48 +00:00
| .expiresAt // 0]
| max // 0
' 2>/dev/null || echo "0"
}
json_expires_for_anthropic_any( ) {
echo " $STATUS_JSON " | jq -r '
[ .auth.oauth.profiles[ ]
| select ( .provider = = "anthropic" and .type = = "oauth" )
| .expiresAt // 0]
| max // 0
' 2>/dev/null || echo "0"
}
json_best_anthropic_profile( ) {
echo " $STATUS_JSON " | jq -r '
[ .auth.oauth.profiles[ ]
| select ( .provider = = "anthropic" and .type = = "oauth" )
| { id: .profileId, exp: ( .expiresAt // 0) } ]
| sort_by( .exp) | reverse | .[ 0] .id // "none"
' 2>/dev/null || echo "none"
}
json_anthropic_api_key_count( ) {
echo " $STATUS_JSON " | jq -r '
[ .auth.providers[ ] | select ( .provider = = "anthropic" ) | .profiles.apiKey]
| max // 0
' 2>/dev/null || echo "0"
}
check_claude_code_auth( ) {
if [ " $USE_JSON " -eq 1 ] ; then
local expires_at
expires_at = $( json_expires_for_claude_cli)
calc_status_from_expires " $expires_at "
return $?
fi
if [ ! -f " $CLAUDE_CREDS " ] ; then
echo "MISSING"
return 1
fi
local expires_at
expires_at = $( jq -r '.claudeAiOauth.expiresAt // 0' " $CLAUDE_CREDS " 2>/dev/null || echo "0" )
calc_status_from_expires " $expires_at "
}
2026-01-30 03:15:10 +01:00
check_openclaw_auth( ) {
2026-01-09 00:32:48 +00:00
if [ " $USE_JSON " -eq 1 ] ; then
local api_keys
api_keys = $( json_anthropic_api_key_count)
if ! [ [ " $api_keys " = ~ ^[ 0-9] +$ ] ] ; then
api_keys = 0
fi
local expires_at
expires_at = $( json_expires_for_anthropic_any)
if [ " $expires_at " -le 0 ] && [ " $api_keys " -gt 0 ] ; then
echo "OK:static"
return 0
fi
calc_status_from_expires " $expires_at "
return $?
fi
2026-01-30 03:15:10 +01:00
if [ ! -f " $OPENCLAW_AUTH " ] ; then
2026-01-09 09:12:19 +10:30
echo "MISSING"
return 1
fi
local expires
expires = $( jq -r '
[ .profiles | to_entries[ ] | select ( .value.provider = = "anthropic" ) | .value.expires]
| max // 0
2026-01-30 03:15:10 +01:00
' " $OPENCLAW_AUTH " 2>/dev/null || echo "0" )
2026-01-09 09:12:19 +10:30
2026-01-09 00:32:48 +00:00
calc_status_from_expires " $expires "
2026-01-09 09:12:19 +10:30
}
# JSON output mode
if [ " $OUTPUT_MODE " = "json" ] ; then
claude_status = $( check_claude_code_auth 2>/dev/null || true )
2026-01-30 03:15:10 +01:00
openclaw_status = $( check_openclaw_auth 2>/dev/null || true )
2026-01-09 09:12:19 +10:30
2026-01-09 00:32:48 +00:00
claude_expires = 0
2026-01-30 03:15:10 +01:00
openclaw_expires = 0
2026-01-09 00:32:48 +00:00
if [ " $USE_JSON " -eq 1 ] ; then
claude_expires = $( json_expires_for_claude_cli)
2026-01-30 03:15:10 +01:00
openclaw_expires = $( json_expires_for_anthropic_any)
2026-01-09 00:32:48 +00:00
else
claude_expires = $( jq -r '.claudeAiOauth.expiresAt // 0' " $CLAUDE_CREDS " 2>/dev/null || echo "0" )
2026-01-30 03:15:10 +01:00
openclaw_expires = $( jq -r '.profiles["anthropic:default"].expires // 0' " $OPENCLAW_AUTH " 2>/dev/null || echo "0" )
2026-01-09 00:32:48 +00:00
fi
2026-01-09 09:12:19 +10:30
jq -n \
--arg cs " $claude_status " \
--arg ce " $claude_expires " \
2026-01-30 03:15:10 +01:00
--arg bs " $openclaw_status " \
--arg be " $openclaw_expires " \
2026-01-09 09:12:19 +10:30
' {
claude_code: { status: $cs , expires_at_ms: ( $ce | tonumber) } ,
2026-01-30 03:15:10 +01:00
openclaw: { status: $bs , expires_at_ms: ( $be | tonumber) } ,
2026-01-09 09:12:19 +10:30
needs_reauth: ( ( $cs | startswith( "EXPIRED" ) or startswith( "EXPIRING" ) or startswith( "MISSING" ) ) or ( $bs | startswith( "EXPIRED" ) or startswith( "EXPIRING" ) or startswith( "MISSING" ) ) )
} '
exit 0
fi
# Simple output mode (for scripts/widgets)
if [ " $OUTPUT_MODE " = "simple" ] ; then
claude_status = $( check_claude_code_auth 2>/dev/null || true )
2026-01-30 03:15:10 +01:00
openclaw_status = $( check_openclaw_auth 2>/dev/null || true )
2026-01-09 09:12:19 +10:30
if [ [ " $claude_status " = = EXPIRED* ] ] || [ [ " $claude_status " = = MISSING* ] ] ; then
echo "CLAUDE_EXPIRED"
exit 1
2026-01-30 03:15:10 +01:00
elif [ [ " $openclaw_status " = = EXPIRED* ] ] || [ [ " $openclaw_status " = = MISSING* ] ] ; then
echo "OPENCLAW_EXPIRED"
2026-01-09 09:12:19 +10:30
exit 1
elif [ [ " $claude_status " = = EXPIRING* ] ] ; then
echo "CLAUDE_EXPIRING"
exit 2
2026-01-30 03:15:10 +01:00
elif [ [ " $openclaw_status " = = EXPIRING* ] ] ; then
echo "OPENCLAW_EXPIRING"
2026-01-09 09:12:19 +10:30
exit 2
else
echo "OK"
exit 0
fi
fi
# Full output mode (default)
echo "=== Claude Code Auth Status ==="
echo ""
# Claude Code credentials
echo "Claude Code (~/.claude/.credentials.json):"
2026-01-09 00:32:48 +00:00
if [ " $USE_JSON " -eq 1 ] ; then
expires_at = $( json_expires_for_claude_cli)
else
expires_at = $( jq -r '.claudeAiOauth.expiresAt // 0' " $CLAUDE_CREDS " 2>/dev/null || echo "0" )
fi
2026-01-09 09:12:19 +10:30
if [ -f " $CLAUDE_CREDS " ] ; then
2026-01-09 00:32:48 +00:00
sub_type = $( jq -r '.claudeAiOauth.subscriptionType // "unknown"' " $CLAUDE_CREDS " 2>/dev/null || echo "unknown" )
rate_tier = $( jq -r '.claudeAiOauth.rateLimitTier // "unknown"' " $CLAUDE_CREDS " 2>/dev/null || echo "unknown" )
echo " Subscription: $sub_type "
echo " Rate tier: $rate_tier "
fi
2026-01-09 09:12:19 +10:30
2026-01-09 00:32:48 +00:00
if [ " $expires_at " -le 0 ] ; then
echo -e " Status: ${ RED } NOT FOUND ${ NC } "
echo " Action needed: Run 'claude setup-token'"
else
now_ms = $(( $( date +%s) * 1000 ))
2026-01-09 09:12:19 +10:30
diff_ms = $(( expires_at - now_ms))
hours = $(( diff_ms / 3600000 ))
mins = $(( ( diff_ms % 3600000 ) / 60000 ))
if [ " $diff_ms " -lt 0 ] ; then
echo -e " Status: ${ RED } EXPIRED ${ NC } "
echo " Action needed: Run 'claude setup-token' or re-authenticate"
elif [ " $diff_ms " -lt 3600000 ] ; then
echo -e " Status: ${ YELLOW } EXPIRING SOON ( ${ mins } m remaining) ${ NC } "
echo " Consider running: claude setup-token"
else
echo -e " Status: ${ GREEN } OK ${ NC } "
echo " Expires: $( date -d @$(( expires_at/1000)) ) ( ${ hours } h ${ mins } m) "
fi
fi
echo ""
2026-01-30 03:15:10 +01:00
echo "OpenClaw Auth (~/.openclaw/agents/main/agent/auth-profiles.json):"
2026-01-09 00:32:48 +00:00
if [ " $USE_JSON " -eq 1 ] ; then
best_profile = $( json_best_anthropic_profile)
expires = $( json_expires_for_anthropic_any)
api_keys = $( json_anthropic_api_key_count)
else
2026-01-09 09:12:19 +10:30
best_profile = $( jq -r '
.profiles | to_entries
| map( select ( .value.provider = = "anthropic" ) )
| sort_by( .value.expires) | reverse
| .[ 0] .key // "none"
2026-01-30 03:15:10 +01:00
' " $OPENCLAW_AUTH " 2>/dev/null || echo "none" )
2026-01-09 09:12:19 +10:30
expires = $( jq -r '
[ .profiles | to_entries[ ] | select ( .value.provider = = "anthropic" ) | .value.expires]
| max // 0
2026-01-30 03:15:10 +01:00
' " $OPENCLAW_AUTH " 2>/dev/null || echo "0" )
2026-01-09 00:32:48 +00:00
api_keys = 0
fi
2026-01-09 09:12:19 +10:30
2026-01-09 00:32:48 +00:00
echo " Profile: $best_profile "
if [ " $expires " -le 0 ] && [ " $api_keys " -gt 0 ] ; then
echo -e " Status: ${ GREEN } OK ${ NC } (API key) "
elif [ " $expires " -le 0 ] ; then
echo -e " Status: ${ RED } NOT FOUND ${ NC } "
2026-01-30 03:15:10 +01:00
echo " Note: Run 'openclaw doctor --yes' to sync from Claude Code"
2026-01-09 00:32:48 +00:00
else
now_ms = $(( $( date +%s) * 1000 ))
2026-01-09 09:12:19 +10:30
diff_ms = $(( expires - now_ms))
hours = $(( diff_ms / 3600000 ))
mins = $(( ( diff_ms % 3600000 ) / 60000 ))
if [ " $diff_ms " -lt 0 ] ; then
echo -e " Status: ${ RED } EXPIRED ${ NC } "
2026-01-30 03:15:10 +01:00
echo " Note: Run 'openclaw doctor --yes' to sync from Claude Code"
2026-01-09 09:12:19 +10:30
elif [ " $diff_ms " -lt 3600000 ] ; then
echo -e " Status: ${ YELLOW } EXPIRING SOON ( ${ mins } m remaining) ${ NC } "
else
echo -e " Status: ${ GREEN } OK ${ NC } "
echo " Expires: $( date -d @$(( expires/1000)) ) ( ${ hours } h ${ mins } m) "
fi
fi
echo ""
echo "=== Service Status ==="
2026-01-30 03:15:10 +01:00
if systemctl --user is-active openclaw >/dev/null 2>& 1; then
echo -e " OpenClaw service: ${ GREEN } running ${ NC } "
2026-01-09 09:12:19 +10:30
else
2026-01-30 03:15:10 +01:00
echo -e " OpenClaw service: ${ RED } NOT running ${ NC } "
2026-01-09 09:12:19 +10:30
fi