Authdog

Developers guide

Python Integration

Authdog's Python integration is unreleased and source-only; authdog-fastapi is not on PyPI. This guide consumes reviewed, pinned source from packages/python and wires it into FastAPI, Django, Flask, Starlette, and aiohttp.

Prerequisites

  • Python 3.10 or newer.
  • An Authdog environment and its publishable public key (pk_...).
  • A pinned commit or reviewed source snapshot from packages/python.
  • A frontend or client that obtains a session for the same Authdog environment.

The source declares httpx as its base dependency, with framework extras for FastAPI 0.110, Django 4.2, Flask 3.0, Starlette 0.37, and aiohttp 3.9. Review and pin source before adopting it, there's no registry release, version resolution, or provenance check available.

Implementation

1. Construct the binding

Each framework module exports an Authdog binding, constructed with the environment public key:

import os
from authdog.fastapi import Authdog

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

The core reads authdog-session first, then Authorization: Bearer <token>, resolving identity through the environment's OIDC userinfo endpoint into an AuthdogContext.

2. Resolve vs. enforce

Use session when anonymous and authenticated responses are both valid:

@app.get("/")
async def index(ctx=Depends(authdog.session)):
    return {"authenticated": ctx.is_authenticated}

Use require_auth as the actual authentication gate, it rejects unauthenticated requests with 401:

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

Missing, invalid, or failed userinfo requests produce anonymous context rather than authenticating the request.

3. Match your framework's shape

Django: authdog.session(request) and @authdog.require_auth. Flask: authdog.session() and @authdog.require_auth. Starlette: await authdog.session(request) and await authdog.require_auth(request). aiohttp: await authdog.session(request) and @authdog.require_auth.

Logout helpers clear the local cookie and redirect per framework convention, they don't revoke bearer tokens or end an upstream provider session.

Security considerations

  • session is informational; require_auth is the enforcement boundary, every protected route must use it.
  • Apply role, permission, and ownership checks after require_auth: 401 for missing auth, 403 for insufficient permission.
  • Don't use fetch_user=False as authentication, it exposes an unverified token while leaving is_authenticated false.
  • Keep the public key in configuration so environments stay explicit, hard-coding it makes dev/prod mix-ups easier.
  • Avoid logging cookies and bearer tokens.

Validation checklist

  • Python runtime is 3.10 or newer.
  • Integration source is reviewed and pinned to a commit.
  • No deployment step expects authdog-fastapi from PyPI.
  • Anonymous route returns is_authenticated == False for missing or invalid tokens.
  • Protected route returns 401 without a validated user.
  • Authorization failure returns 403 after authentication.
  • Logs redact cookies and bearer tokens.

Troubleshooting

Dependency resolution can't find authdog-fastapi: expected, no PyPI release exists, confirm the build uses the reviewed source snapshot.

Every request is anonymous: verify the client sends authdog-session or a bearer header for the same environment, then check userinfo reachability.

Route resolves context but remains public: replace informational session use with require_auth at that route.

Next steps

  • Review Python authentication for source installation and session enforcement.
  • Review Python access control, verifying claim names against your environment.
  • Read Backend requests for the shared validation model.
  • Track the source repository for an actual authdog-fastapi release before switching to registry installation.