FastAPI setup
This guide shows an example of setting up a FastAPI app with Zitadel authentication.
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request, Security, Depends
from pydantic import HttpUrl
from fastapi_zitadel_auth import ZitadelAuth
from fastapi_zitadel_auth.user import DefaultZitadelUser
from fastapi_zitadel_auth.exceptions import ForbiddenException
# IDs from Zitadel console
CLIENT_ID = 'your-zitadel-client-id'
PROJECT_ID = 'your-zitadel-project-id'
# Create a ZitadelAuth object usable as a FastAPI dependency
zitadel_auth = ZitadelAuth(
issuer_url=HttpUrl('https://your-instance-xyz.zitadel.cloud'),
project_id=PROJECT_ID,
app_client_id=CLIENT_ID,
allowed_scopes={
"openid": "OpenID Connect",
"email": "Email",
"profile": "Profile",
"urn:zitadel:iam:org:project:id:zitadel:aud": "Audience",
"urn:zitadel:iam:org:projects:roles": "Roles",
}
)
# Create a dependency to validate that the user has the required role
async def validate_is_admin_user(user: DefaultZitadelUser = Depends(zitadel_auth)) -> None:
required_role = "admin"
if required_role not in user.claims.project_roles.keys():
raise ForbiddenException(f"User does not have role assigned: {required_role}")
# Load OpenID configuration at startup
@asynccontextmanager
async def lifespan(app: FastAPI): # noqa
await zitadel_auth.openid_config.load_config()
yield
# Create a FastAPI app and configure Swagger UI
app = FastAPI(
title="fastapi-zitadel-auth demo",
lifespan=lifespan,
swagger_ui_oauth2_redirect_url="/oauth2-redirect",
swagger_ui_init_oauth={
"usePkceWithAuthorizationCodeGrant": True,
"clientId": CLIENT_ID,
"scopes": " ".join( # defining the pre-selected scope ticks in the Swagger UI
[
"openid",
"profile",
"email",
"urn:zitadel:iam:org:projects:roles",
"urn:zitadel:iam:org:project:id:zitadel:aud",
]
),
},
)
# Endpoint that requires a user to be authenticated and have the admin role
@app.get(
"/api/protected/admin",
summary="Protected endpoint, requires admin role",
dependencies=[Security(validate_is_admin_user)],
)
def protected_for_admin(request: Request):
user = request.state.user
return {"message": "Hello world!", "user": user}
# Endpoint that requires a user to be authenticated and have a specific scope
@app.get(
"/api/protected/scope",
summary="Protected endpoint, requires a specific scope",
dependencies=[Security(zitadel_auth, scopes=["scope1"])],
)
def protected_by_scope(request: Request):
user = request.state.user
return {"message": "Hello world!", "user": user}
Customizing OpenAPI documentation
You can optionally customize how the authentication scheme appears in Swagger UI:
zitadel_auth = ZitadelAuth(
...,
scheme_name="ZitadelAuth", # Optional (default: "ZitadelAuthorizationCodeBearer")
description="OAuth2 authentication via Zitadel", # Optional
)
Optional parameters
Both scheme_name and description are optional and have sensible defaults. Only customize them if you want to change how the authentication scheme appears in your API documentation.
CORS Middleware
For production you may need to add a CORS middleware to your FastAPI app.