Add /auth/verify endpoint for L1 token verification

L1 servers call this endpoint to verify tokens during auth callback.
Returns user info if token is valid, 401 if invalid or revoked.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-11 15:49:39 +00:00
parent 8c4a30d18f
commit 655f533439

View File

@@ -1,14 +1,15 @@
"""
Authentication routes for L2 server.
Handles login, registration, and logout.
Handles login, registration, logout, and token verification.
"""
import hashlib
from datetime import datetime, timezone
from fastapi import APIRouter, Request, Form
from fastapi import APIRouter, Request, Form, HTTPException, Depends
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from artdag_common import render
from artdag_common.middleware import wants_html
@@ -17,6 +18,7 @@ from ..config import settings
from ..dependencies import get_templates, get_user_from_cookie
router = APIRouter()
security = HTTPBearer(auto_error=False)
@router.get("/login", response_class=HTMLResponse)
@@ -173,3 +175,49 @@ async def logout(request: Request):
response = RedirectResponse(url="/", status_code=302)
response.delete_cookie("auth_token")
return response
@router.get("/verify")
async def verify_token(
request: Request,
credentials: HTTPAuthorizationCredentials = Depends(security),
):
"""
Verify a token is valid.
Called by L1 servers to verify tokens during auth callback.
Returns user info if valid, 401 if not.
"""
import db
from auth import verify_token as verify_jwt, get_token_claims
# Get token from Authorization header or query param
token = None
if credentials:
token = credentials.credentials
else:
# Try Authorization header manually (for clients that don't use Bearer format)
auth_header = request.headers.get("Authorization", "")
if auth_header.startswith("Bearer "):
token = auth_header[7:]
if not token:
raise HTTPException(401, "No token provided")
# Verify JWT signature and expiry
username = verify_jwt(token)
if not username:
raise HTTPException(401, "Invalid or expired token")
# Check if token is revoked
claims = get_token_claims(token)
if claims:
token_hash = hashlib.sha256(token.encode()).hexdigest()
if await db.is_token_revoked(token_hash):
raise HTTPException(401, "Token has been revoked")
return {
"valid": True,
"username": username,
"claims": claims,
}