How to Create Public Endpoints¶
This guide shows how to mark specific endpoints as publicly accessible, bypassing JWT token validation.
The Problem¶
By default, all routes require a valid JWT token. Public endpoints like health checks, login pages, or public APIs need to opt out of authentication.
Using @allow_anonymous¶
Apply the @allow_anonymous decorator to any controller method:
from pico_fastapi import controller, get
from pico_client_auth import allow_anonymous
@controller(prefix="/api")
class ApiController:
@get("/health")
@allow_anonymous
async def health(self):
"""No token required."""
return {"status": "ok"}
@get("/version")
@allow_anonymous
async def version(self):
"""Also public."""
return {"version": "1.0.0"}
@get("/data")
async def get_data(self):
"""This still requires a token."""
return {"secret": "data"}
How It Works¶
The middleware checks for the _pico_allow_anonymous attribute on the matched endpoint function:
- Route is matched via Starlette's
route.matches(scope) - If the endpoint has
_pico_allow_anonymous = True, skip auth entirely - The request proceeds to the handler without any token validation
SecurityContextwill be empty (get()returnsNone)
Accessing Optional Claims on Anonymous Endpoints¶
On @allow_anonymous endpoints, the middleware skips token validation entirely. If you want to optionally read claims when a token is present (but not require it), you'll need to handle that in the endpoint:
from pico_client_auth import SecurityContext, allow_anonymous
@get("/greeting")
@allow_anonymous
async def greeting(self):
claims = SecurityContext.get() # None if no token
if claims:
return {"message": f"Hello, {claims.email}!"}
return {"message": "Hello, guest!"}
Note
On @allow_anonymous routes, the middleware does not validate the token even if one is provided. SecurityContext will be empty.
Common Use Cases¶
| Endpoint | Why Anonymous |
|---|---|
/health, /ready | Load balancer / k8s probes |
/version, /info | Public metadata |
/docs, /openapi.json | FastAPI auto-generated docs |
/auth/login | Login page or token exchange |
/public/* | Public content APIs |
FastAPI Built-in Routes¶
FastAPI's built-in routes (/docs, /redoc, /openapi.json) are not controller routes, so the auth middleware won't affect them. They are handled by FastAPI before the middleware runs for route matching.