L2: verify auth state with account on each request
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m49s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m49s
When user has artdag_session cookie, periodically (every 30s) check account's /auth/internal/check-device endpoint. If account says the device is no longer active (SSO logout), clear the cookie immediately. Prevents stale sign-in after logging out from another app. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ from pathlib import Path
|
|||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
import httpx
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import JSONResponse, HTMLResponse, RedirectResponse
|
from fastapi.responses import JSONResponse, HTMLResponse, RedirectResponse
|
||||||
|
|
||||||
@@ -72,8 +73,43 @@ def create_app() -> FastAPI:
|
|||||||
):
|
):
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
||||||
# Already logged in — pass through
|
# Already logged in — verify account hasn't revoked auth
|
||||||
if get_user_from_cookie(request):
|
if get_user_from_cookie(request):
|
||||||
|
device_id = getattr(request.state, "device_id", None)
|
||||||
|
if device_id:
|
||||||
|
# Check every 30s whether account still considers this device active
|
||||||
|
check_at = request.cookies.get("auth_check_at")
|
||||||
|
now = time.time()
|
||||||
|
stale = True
|
||||||
|
if check_at:
|
||||||
|
try:
|
||||||
|
stale = (now - float(check_at)) > 30
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
pass
|
||||||
|
if stale and settings.internal_account_url:
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient(timeout=3) as client:
|
||||||
|
resp = await client.get(
|
||||||
|
f"{settings.internal_account_url.rstrip('/')}"
|
||||||
|
f"/auth/internal/check-device"
|
||||||
|
f"?device_id={device_id}&app=artdag_l2"
|
||||||
|
)
|
||||||
|
if resp.status_code == 200 and not resp.json().get("active"):
|
||||||
|
# Account revoked — clear cookie
|
||||||
|
response = await call_next(request)
|
||||||
|
response.delete_cookie("artdag_session")
|
||||||
|
response.delete_cookie("pnone_at")
|
||||||
|
response.delete_cookie("auth_check_at")
|
||||||
|
return response
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# Update check timestamp
|
||||||
|
response = await call_next(request)
|
||||||
|
response.set_cookie(
|
||||||
|
"auth_check_at", str(now), max_age=60,
|
||||||
|
httponly=True, samesite="lax", secure=True,
|
||||||
|
)
|
||||||
|
return response
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
||||||
# Check cooldown — don't re-check within 5 minutes
|
# Check cooldown — don't re-check within 5 minutes
|
||||||
|
|||||||
Reference in New Issue
Block a user