Authdog

Backend requests

Last updated Oct 18, 2026
View as Markdown

Your backend never sees a password. It checks the session Authdog already issued, then allows or denies the route.

If you're using an Authdog SDK, the middleware does that check for you. This page is the model underneath, and the shape of a protected endpoint when you want to see it yourself.

What arrives at your backend

After a successful sign-in, Authdog issues a signed JWT. Every request from your frontend carries it one of two ways:

  • The authdog-session cookie (set automatically by the browser SDK).
  • An Authorization: Bearer <token> header (for native apps and API clients).

Read whichever one is present, and validate it before you trust anything else on the request.

The verification model

Validation needs two inputs: your environment's public key (pk_...) and the identity provider's userinfo endpoint. The SDK parses the public key once at startup. A malformed key, or a key whose identity host isn't on the trusted allowlist, fails immediately, not on the first real request. On each request the SDK reads the token, checks it against userinfo, and returns the current user. See Sessions and tokens and Authentication for the full model.

Protecting a route

Resolving a session only tells you who the caller is, or that there isn't one. The enforcement point is a guard that rejects unauthenticated requests with 401. In FastAPI that guard is a dependency:

import os
from fastapi import Depends, FastAPI
from authdog.fastapi import Authdog

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

@app.get("/me")
async def me(user=Depends(authdog.require_auth)):
    # reached only for a valid session; 401 otherwise
    return user

Every SDK has the same shape: a resolver you can read when you're shaping a response, and a require_auth gate that is the security boundary. A resolved session is not a permission grant. Pair it with your environment's authorization model.

Service-to-service (M2M)

For a request with no end user (a cron job, or one backend calling another), use machine-to-machine auth. An M2M application uses the OAuth 2.0 client_credentials grant to get a token, then sends it as Authorization: Bearer <token>. The receiving service validates it the same way it validates a user session, and resolves a service identity instead of a person.

Calling the REST API

Once a request is authenticated, your backend can call the Authdog REST API at https://api.authdog.com/v1/... to read users, organizations, and more. The language clients are typed wrappers over that API, so you rarely build the raw request yourself.

Language clients for that API: Python, Node.js, Go, Rust, Java, C#, and Zig. Python is authdog 0.1.1 on PyPI. The others ship from authdog/sdk.

Shipped backend SDKs

All expose the same three primitives: session resolver, require_auth gate, and logout handler:

  • Node: Express, Fastify, Hono, and Koa
  • Python: FastAPI, Django, Flask, Starlette, aiohttp
  • Go
  • Rust
  • Kotlin

Events and webhooks

Identity also emits events (SIGNIN_SUCCESS, NEW_USER, and others) your backend can subscribe to. Webhooks are HMAC-signed (X-Authdog-Signature: t=..., v1=...), and delivery is retried. Verify the signature before you act on the payload. See Events and webhooks for the catalog, the signature check, and retry behavior.

Learn more