feat: Claude CLI OAuth token expiry warning
New GET /auth/status endpoint reads ~/.claude/.credentials.json and returns hours remaining + warning flag. UI shows a dismissible amber banner when < 24h remain, turning red if expired. Checked on page load and every 30 minutes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
37
cortex/routers/auth.py
Normal file
37
cortex/routers/auth.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
Claude CLI OAuth token status.
|
||||
|
||||
GET /auth/status — returns expiry info; warns when < WARN_HOURS remain
|
||||
"""
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from fastapi import APIRouter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/auth")
|
||||
|
||||
CREDENTIALS_PATH = Path.home() / ".claude" / ".credentials.json"
|
||||
WARN_HOURS = 24 # show warning banner when fewer than this many hours remain
|
||||
|
||||
|
||||
@router.get("/status")
|
||||
async def auth_status() -> dict:
|
||||
try:
|
||||
data = json.loads(CREDENTIALS_PATH.read_text())
|
||||
oauth = data["claudeAiOauth"]
|
||||
expires_at_ms = oauth["expiresAt"]
|
||||
expires_dt = datetime.fromtimestamp(expires_at_ms / 1000, tz=timezone.utc)
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
hours_remaining = (expires_dt - now).total_seconds() / 3600
|
||||
return {
|
||||
"ok": True,
|
||||
"expires_at": expires_dt.isoformat(),
|
||||
"hours_remaining": round(hours_remaining, 1),
|
||||
"warning": hours_remaining < WARN_HOURS,
|
||||
"expired": hours_remaining <= 0,
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning("auth status check failed: %s", e)
|
||||
return {"ok": False, "error": str(e), "warning": True, "expired": False}
|
||||
Reference in New Issue
Block a user