Authdog
Log In

Python · Authentication

Basic authentication

Add sign-in to a Python backend, then prove a request with no token stays anonymous.

This walkthrough uses FastAPI. The same shape applies to Django, Flask, Starlette, and 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]"

There is no PyPI package for these bindings. Swap [fastapi] for [django], [flask], [starlette], or [aiohttp], and pin the commit your deploy uses. If pip install authdog succeeds, you got the management API client (authdog 0.1.1), which does not include authdog.fastapi.

Configure the public key

export PK_AUTHDOG="pk_..."

Keep the key in the environment. Do not hard-code it. A malformed key, or one whose identity host is not allowlisted, fails at startup. You want that failure here, not on the first real 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 an AuthdogContext (token, user, is_authenticated, user_info). It does not raise. Call / with no cookie and no bearer token. You should get is_authenticated false and a 200. That route is for pages where both answers are fine.

Protect a route

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

require_auth is the gate. It raises 401 when the request is not authenticated, and otherwise hands you the user. Put it on every route that must not be public. Reading is_authenticated from session is fine when you are choosing what to render. It will not stop the handler. The context is cached on request.state, so using both on one request calls userinfo at most once. Call /me with no token and expect 401.

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 it has checked against open redirects. Hit /logout, then call /me again. You want 401.

Skip the userinfo round-trip

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

Use this when something else already validates the token. ctx.token is set, and is_authenticated stays false. That false is intentional. Do not treat the token as a signed-in user.

Next steps