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:
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user