Use case
Add authentication to FastAPI
The AscendKit Python SDK protects FastAPI routes with a dependency that verifies access tokens locally against AscendKit's JWKS — no shared secret and no network call per request. It also covers OAuth sign-in via build_authorize_url, plus reading and updating users. What it does not provide is rendered sign-in UI or password and magic-link flows; those live in the JS SDK, whose auth runtime is Next.js-only. Be clear which half you need before you start.
How it works
- 1. Install the SDKAdd the AscendKit Python SDK and configure your project public key.
- 2. Protect routesUse get_current_user_dependency to require a valid access token on a route. Verified claims expose the usr_ ID as sub and the user's email.
- 3. ExtendLayer on transactional email, surveys, and webhooks from the same project without adding new vendors.
How does FastAPI authentication work with AscendKit?
Your frontend signs the user in and receives a short-lived RS256 access token. FastAPI verifies that token locally against AscendKit's JWKS and resolves it to a user. There is no shared secret and no network call to AscendKit on each request.
Local verification is the part worth understanding. The SDK fetches the public keys once, caches them in memory for an hour, and validates the signature itself. Token checks stay fast under load and keep working through a brief AscendKit outage.
Be clear about the split before you start: the Python SDK verifies tokens, manages users, and can start an OAuth redirect via build_authorize_url. It does not render sign-in UI and does not handle password or magic-link flows -- those need the JS SDK, whose auth runtime is Next.js-only.
from fastapi import FastAPI, Depends, Header, HTTPException
from ascendkit import AccessTokenVerifier, AuthError
app = FastAPI()
verifier = AccessTokenVerifier()
async def get_current_user(authorization: str = Header()) -> dict:
token = authorization.removeprefix("Bearer ").strip()
try:
return await verifier.verify_async(token)
except AuthError as e:
raise HTTPException(status_code=e.status_code, detail=str(e))
@app.get("/api/profile")
async def profile(user: dict = Depends(get_current_user)):
return {"email": user["email"], "id": user["sub"]}Which claims should you store in your own tables?
The `sub` claim, and nothing else. It carries the prefixed `usr_` ID, and that is the foreign key to use everywhere in your schema.
It is stable, it is safe to expose in your own APIs, and it is the same identifier that email, journeys, and surveys address -- so a row in your database can be joined to that user's lifecycle without a second mapping table.
Do not key on email. People change it, and treating it as an identity makes that change a data migration.
| Claim | Contains | Use for |
|---|---|---|
| sub | usr_abc123 | Foreign key in your tables |
| Verified email address | Display and contact, never identity |
Troubleshooting
Every request returns 401 in production but works locally
Cause: The token was issued against one environment and is being verified against another. Development and production have different keys.
Fix: Confirm the public key on the backend belongs to the same environment the frontend authenticates against.
Intermittent 503s under load
Cause: The JWKS cache expired and several requests tried to refresh it at once.
Fix: Treat 503 as retryable, not as an auth failure. Never sign a user out on a 503 -- that is our outage, not their session expiring.
FAQ
Does the Python SDK support FastAPI natively?
Yes. The Python SDK ships a FastAPI integration with access-token verification you can use as a route dependency.
Is anonymous access supported?
No. Every interaction links to a registered project user, so requests are always scoped to a usr_ record.
Related guides
- Add auth to a Hono API — the same verification on an edge runtime.
- Python SDK reference — the full API surface, including webhooks and server-side analytics.
- Add auth and email to Next.js — the frontend half that issues the tokens FastAPI verifies.
Start with one API key
Auth, email, surveys, and journeys share one user record, so you ship this without stitching vendors together.
Start free