Authdog
Log In

Python · Authentication

Basic authentication

Add sign-in to a Python backend with Authdog. This guide uses FastAPI. Per-framework docs: FastAPI, Django, Flask, Starlette, aiohttp. Hub: Python backends.

Install from source

git clone https://github.com/authdog/web-sdk.git
cd web-sdk
python -m pip install "./packages/python[fastapi]"

These FastAPI session bindings are source-only. Swap [fastapi] for [django], [flask], [starlette], or [aiohttp], and pin the repository commit in deployment automation.

pip install authdog is a different package: the management API client (authdog 0.1.1 on PyPI). It does not install authdog.fastapi.

Configure the public key

export PK_AUTHDOG="pk_..."

Set it as an environment variable, never hard-code it. The key is validated once at startup, a malformed key or one whose identity host isn't allowlisted raises immediately instead of failing on the first request.

Resolve the session

import os
from fastapi import Depends, FastAPI
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}

authdog.session reads the token, calls userinfo, and returns a typed AuthdogContext (token, user, is_authenticated, user_info). It never raises, a missing or invalid token just yields is_authenticated == False.

Protect a route

@app.get("/me")
async def me(user=Depends(authdog.require_auth)):
    return user

require_auth is the real enforcement point: it raises 401 for unauthenticated requests and otherwise returns the user directly. Every protected route must depend on it, reading ctx.is_authenticated from session is fine for shaping a response, but it isn't a security boundary on its own. The resolved context is cached on request.state, so combining session and require_auth on one request makes at most one userinfo call.

Add a logout handler

@app.get("/logout")
async def logout(request: Request):
    return authdog.logout(request)

authdog.logout(request) expires the authdog-session cookie (HttpOnly, SameSite=Lax, Secure in production) and redirects to a redirect_uri sanitized against open redirects.

Skip the userinfo round-trip

authdog = Authdog(public_key=os.environ["PK_AUTHDOG"], fetch_user=False)

For high-throughput services validating the token elsewhere: ctx.token is populated but is_authenticated stays False, you own validation.

Next steps