From f1d80a1777b66fe124cfa374ad23d532aace5667 Mon Sep 17 00:00:00 2001 From: giles Date: Wed, 25 Feb 2026 01:42:09 +0000 Subject: [PATCH] L2: verify auth state with account on each request 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 --- l2/app/__init__.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/l2/app/__init__.py b/l2/app/__init__.py index fbc713a..982dfac 100644 --- a/l2/app/__init__.py +++ b/l2/app/__init__.py @@ -10,6 +10,7 @@ from pathlib import Path from contextlib import asynccontextmanager from urllib.parse import quote +import httpx from fastapi import FastAPI, Request from fastapi.responses import JSONResponse, HTMLResponse, RedirectResponse @@ -72,8 +73,43 @@ def create_app() -> FastAPI: ): 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): + 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) # Check cooldown — don't re-check within 5 minutes