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.
|
Authentication routes for L2 server.
|
||||||
|
|
||||||
Handles login, registration, and logout.
|
Handles login, registration, logout, and token verification.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
from datetime import datetime, timezone
|
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.responses import HTMLResponse, RedirectResponse
|
||||||
|
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||||
|
|
||||||
from artdag_common import render
|
from artdag_common import render
|
||||||
from artdag_common.middleware import wants_html
|
from artdag_common.middleware import wants_html
|
||||||
@@ -17,6 +18,7 @@ from ..config import settings
|
|||||||
from ..dependencies import get_templates, get_user_from_cookie
|
from ..dependencies import get_templates, get_user_from_cookie
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
security = HTTPBearer(auto_error=False)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/login", response_class=HTMLResponse)
|
@router.get("/login", response_class=HTMLResponse)
|
||||||
@@ -173,3 +175,49 @@ async def logout(request: Request):
|
|||||||
response = RedirectResponse(url="/", status_code=302)
|
response = RedirectResponse(url="/", status_code=302)
|
||||||
response.delete_cookie("auth_token")
|
response.delete_cookie("auth_token")
|
||||||
return response
|
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