Files
NestQuest/api/routes_admin.py
T

66 lines
2.3 KiB
Python
Raw Normal View History

2026-09-23 00:37:30 -04:00
"""Admin-plane routes for the NestQuest API service.
The admin plane (``/api/v1/admin/*``, D-012) serves the admin PWA.
Every route on :data:`router` requires a valid Authentik OIDC JWT
whose ``groups`` claim names ``nestquest-admins``, through the ONE
reusable dependency :func:`api.auth.require_admin` (declared once at
the router level, so each later admin route added to this router
inherits the check). The panel service token is refused outright on
this plane (403), never treated as a JWT.
2026-09-23 00:37:30 -04:00
This task is the AUTH probe only: the ping route is a thin adapter
that performs NO business logic and NO auth of its own — it reuses the
router's already-verified claims (FastAPI caches a dependency's result
per request, so the check runs exactly once) and returns the status
plus the token's subject.
2026-09-23 00:37:30 -04:00
"""
from __future__ import annotations
from typing import Annotated
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from api.auth import require_admin
2026-09-23 00:37:30 -04:00
#: All admin-plane routes share this router; the ONE admin dependency
#: (service-token refusal + JWT verification + nestquest-admins group
#: gate) is attached HERE so every admin route (current and later)
#: requires it.
2026-09-23 00:37:30 -04:00
router = APIRouter(
prefix="/api/v1/admin",
dependencies=[Depends(require_admin)],
2026-09-23 00:37:30 -04:00
)
class AdminPingResponse(BaseModel):
"""The probe body: the status plus the verified token's subject."""
status: str
#: The JWT's ``sub`` claim — the subject the admin PWA authenticated
#: as. ``None`` only for a verified token that carries no ``sub``.
sub: str | None
@router.get("/ping", summary="Admin plane probe")
async def admin_ping(
claims: Annotated[dict[str, object], Depends(require_admin)],
2026-09-23 00:37:30 -04:00
) -> AdminPingResponse:
"""Return 200 for a verified JWT naming the nestquest-admins group.
2026-09-23 00:37:30 -04:00
Requires a valid Authentik JWT with the admin group (checked by the
router's shared :func:`~api.auth.require_admin` dependency — the
ONE check; this handler performs NO auth of its own). ``claims``
is the SAME verified-claims dict that dependency produced (FastAPI's
2026-09-23 00:37:30 -04:00
per-request dependency cache), so the token is verified exactly
once per request.
"""
sub = claims.get("sub")
return AdminPingResponse(
status="ok",
sub=sub if isinstance(sub, str) else None,
)
__all__ = ["router"]