enforce: auth required on ALL API endpoints except login
Some checks failed
Deploy Tracker / deploy (push) Failing after 4s
Some checks failed
Deploy Tracker / deploy (push) Failing after 4s
This commit is contained in:
parent
8b993abc37
commit
0840e38849
@ -89,47 +89,48 @@ app = FastAPI(
|
|||||||
lifespan=lifespan,
|
lifespan=lifespan,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Paths that don't require auth
|
# API paths that don't require auth
|
||||||
NO_AUTH_PATHS = {"/health", "/docs", "/openapi.json", "/ws"}
|
NO_AUTH_API = {"/api/v1/auth/login"}
|
||||||
|
|
||||||
|
|
||||||
@app.middleware("http")
|
@app.middleware("http")
|
||||||
async def auth_middleware(request: Request, call_next):
|
async def auth_middleware(request: Request, call_next):
|
||||||
"""Verify token for REST API requests."""
|
"""Verify token for all API requests (except login)."""
|
||||||
path = request.url.path
|
path = request.url.path
|
||||||
|
|
||||||
# Skip auth for non-API paths and excluded paths
|
if not path.startswith("/api/") or path in NO_AUTH_API:
|
||||||
if not path.startswith("/api/") and path not in NO_AUTH_PATHS:
|
return await call_next(request)
|
||||||
# WS and health don't need REST auth
|
|
||||||
pass
|
# Extract token from header or query param
|
||||||
elif path.startswith("/api/"):
|
|
||||||
auth_header = request.headers.get("authorization", "")
|
auth_header = request.headers.get("authorization", "")
|
||||||
token = None
|
token = None
|
||||||
if auth_header.startswith("Bearer "):
|
if auth_header.startswith("Bearer "):
|
||||||
token = auth_header[7:]
|
token = auth_header[7:]
|
||||||
elif request.query_params.get("token"):
|
elif request.query_params.get("token"):
|
||||||
token = request.query_params["token"]
|
token = request.query_params["token"]
|
||||||
if token:
|
|
||||||
# Check agent token
|
if not token:
|
||||||
|
return JSONResponse(status_code=401, content={"error": "Authentication required"})
|
||||||
|
|
||||||
|
# Resolve member from token
|
||||||
async with async_session() as db:
|
async with async_session() as db:
|
||||||
|
# Try agent token first
|
||||||
result = await db.execute(select(Member).where(Member.token == token))
|
result = await db.execute(select(Member).where(Member.token == token))
|
||||||
member = result.scalar_one_or_none()
|
member = result.scalar_one_or_none()
|
||||||
if member:
|
if not member:
|
||||||
request.state.member = member
|
|
||||||
else:
|
|
||||||
# Try JWT
|
# Try JWT
|
||||||
from tracker.api.auth import decode_jwt
|
from tracker.api.auth import decode_jwt
|
||||||
try:
|
try:
|
||||||
payload = decode_jwt(token)
|
payload = decode_jwt(token)
|
||||||
result = await db.execute(select(Member).where(Member.id == payload["sub"]))
|
result = await db.execute(select(Member).where(Member.id == payload["sub"]))
|
||||||
member = result.scalar_one_or_none()
|
member = result.scalar_one_or_none()
|
||||||
if member:
|
|
||||||
request.state.member = member
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
# Don't enforce auth yet — BFF uses its own token via proxy
|
|
||||||
# TODO: enforce when all clients are updated
|
|
||||||
|
|
||||||
|
if not member:
|
||||||
|
return JSONResponse(status_code=401, content={"error": "Invalid or expired token"})
|
||||||
|
|
||||||
|
request.state.member = member
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user