Skip to content

Exceptions

All exceptions live in fastapi_simple_tinyauth.exceptions and derive from Starlette's HTTPException (which FastAPI's HTTPException also subclasses). Because of that, FastAPI renders them out of the box, and you can register exception_handlers to control the response shape.

The classes

  • TinyauthError — base class for all the errors below. Register a handler for it to catch every package error in one place.
  • UntrustedProxyError — HTTP 403. The request's peer is not a trusted proxy.
  • UnauthenticatedError — HTTP 401. An endpoint required a user but the request was anonymous.
  • ForbiddenError — HTTP 403. The user is authenticated but does not meet a group requirement.

Each accepts an optional detail string:

from fastapi_simple_tinyauth.exceptions import ForbiddenError

raise ForbiddenError("You need the admins group")

Registering handlers

from fastapi.responses import JSONResponse

from fastapi_simple_tinyauth.exceptions import (
    ForbiddenError,
    TinyauthError,
    UnauthenticatedError,
    UntrustedProxyError,
)


@app.exception_handler(UnauthenticatedError)
async def on_unauth(request, exc: UnauthenticatedError) -> JSONResponse:
    return JSONResponse({"error": "unauthenticated", "detail": exc.detail}, status_code=exc.status_code)


@app.exception_handler(ForbiddenError)
async def on_forbidden(request, exc: ForbiddenError) -> JSONResponse:
    return JSONResponse({"error": "forbidden", "detail": exc.detail}, status_code=exc.status_code)


@app.exception_handler(UntrustedProxyError)
async def on_untrusted(request, exc: UntrustedProxyError) -> JSONResponse:
    return JSONResponse({"error": "untrusted_proxy", "detail": exc.detail}, status_code=exc.status_code)


@app.exception_handler(TinyauthError)
async def on_any(request, exc: TinyauthError) -> JSONResponse:
    return JSONResponse({"error": "tinyauth_error", "detail": exc.detail}, status_code=exc.status_code)

A note on UntrustedProxyError

The middleware rejects an untrusted peer before the request reaches your app, emitting a plain-text 403 directly. That rejection does not go through your exception handlers. The UntrustedProxyError handler only fires if an endpoint or one of your own dependencies raises UntrustedProxyError.

See Trusted proxies for the reasoning.