Prerequisites
- Python 3.10+
- An Authdog environment and its public key (
pk_โฆ), available in the Authdog console. - A frontend that signs users in against the same Authdog environment. The
Python SDK validates the session that your frontend establishes โ it reads
the
authdog-sessioncookie (or anAuthorization: Bearer <token>header) and verifies it against the identity provider'suserinfoendpoint.
Install
pip install authdog-fastapi
Installing an extra pulls in the binding for your framework:
pip install "authdog-fastapi[flask]" # Flask
pip install "authdog-fastapi[django]" # Django
fastapi and httpx are the only runtime dependencies.
Configure the public key
Set your Authdog public key as an environment variable rather than hard-coding it:
export PK_AUTHDOG="pk_..."
The key is validated and parsed once at startup โ a malformed key, or one whose identity host is not on the trusted allowlist, raises immediately instead of failing on the first request.
Resolve the session
Create an Authdog instance and use authdog.session as a FastAPI dependency.
It reads the token, calls userinfo, and returns a typed AuthdogContext. It
never raises โ a missing or invalid token simply yields
is_authenticated == False.
import os
from fastapi import Depends, FastAPI, Request
from authdog.fastapi import Authdog
app = FastAPI()
authdog = Authdog(public_key=os.environ["PK_AUTHDOG"])
@app.get("/")
async def index(ctx=Depends(authdog.session)):
return {"authenticated": ctx.is_authenticated}
The context is:
@dataclass
class AuthdogContext:
token: str | None = None
user: Any | None = None
is_authenticated: bool = False
user_info: dict | None = None
Protect a route
authdog.require_auth is the real server-side enforcement point. It raises
HTTPException(401) for unauthenticated requests and otherwise returns the user
object, so a handler can depend on it directly:
@app.get("/me")
async def me(user=Depends(authdog.require_auth)):
return user
Every protected route must depend on require_auth. Reading
ctx.is_authenticated from session is fine for shaping a response, but it is
not a security boundary on its own.
Because the resolved context is cached on request.state, combining session
and require_auth on the same request makes at most one outbound userinfo
call.
Add a logout handler
authdog.logout(request) returns a RedirectResponse that expires the
authdog-session cookie and redirects to the redirect_uri query parameter,
sanitized against open redirects:
@app.get("/logout")
async def logout(request: Request):
return authdog.logout(request)
The cookie is cleared with HttpOnly, SameSite=Lax, and Secure when
ENV=production.
Skip the userinfo round-trip
For high-throughput services that validate the token elsewhere, disable the lookup:
authdog = Authdog(public_key=os.environ["PK_AUTHDOG"], fetch_user=False)
ctx.token is populated but is_authenticated stays False โ you own
validation.
Next steps
- Basic access control โ authorize routes by role and permission on top of the authenticated user.
- Python SDK overview โ the framework matrix and feature tour.