FastAPI API#

FastAPI integration for py oidc auth.

The FastApiOIDCAuth class provides:

  • Dependencies for protected and optional routes

  • An fastapi.APIRouter with standard authentication endpoints

Install:

pip install py-oidc-auth[fastapi]
conda install -c conda-forge py-oidc-fastapi

Basic usage

from fastapi import FastAPI
from py_oidc_auth.fastapi_auth import FastApiOIDCAuth

app = FastAPI()

auth = FastApiOIDCAuth(
    client_id="my client",
    discovery_url="https://idp.example.org/realms/demo/.well-known/openid-configuration",
    client_secret="secret",
    scopes="myscope profile email",
    broker_mode=True,
    broker_store_url="postgresql+asyncpg://user:pw@db/myapp",
)

app.include_router(auth.create_auth_router(prefix="/api"))

@app.get("/me")
async def me(token = auth.required()):
    return {"sub": token.sub}
class py_oidc_auth.fastapi_auth.FastApiOIDCAuth(client_id: str = '', discovery_url: str = '', client_secret: str | None = None, scopes: str = 'profile email', audience: str | None = None, appname: str = 'py-oidc-auth', proxy: str = '', claims: Dict[str, Any] | None = None, offline_access: bool = True, timeout_sec: int = 10, jwks_uri: str | None = None, issuer: str | None = None, broker_mode: bool = False, broker_store_url: str | None = None, broker_store_obj: BrokerStore | None = None, broker_audience: str = 'py-oidc-auth', trusted_issuers: list[str] | None = None, broker_jwks_path: str = '/auth/v2/.well-known/jwks.json')#

Reusable OpenID Connect helper for FastAPI.

The class extends OIDCAuth and adds a FastAPI friendly surface. All broker logic is inherited from the base class and is therefore available to every framework adapter.

You typically:

required(claims: Dict[str, Any] | None = None, scopes: str = '') Any#

Return a dependency that enforces authentication.

The dependency validates the bearer token from the Authorization header. In broker mode verifies broker JWTs. In passthrough mode verifies IDP tokens via the discovery JWKS. If validation fails, a FastAPI fastapi.HTTPException is raised.

Parameters:
  • claims – Optional claim constraints.

  • scopes – Space separated scope names that the token must contain.

Returns:

A ready to use fastapi.Security() dependency.

Example

@app.get("/admin")
async def admin(token: IDToken = auth.required(scopes="admin")):
    return {"sub": token.sub}
optional(claims: Dict[str, Any] | None = None, scopes: str = '') Any#

Return a dependency that accepts anonymous requests.

When no bearer token is present, or when token validation fails, the dependency returns None.

Parameters:
  • claims – Optional claim constraints.

  • scopes – Space separated scope names.

Returns:

A ready to use fastapi.Security() dependency.

Example

@app.get("/feed")
async def feed(token: Optional[IDToken] = auth.optional()):
    if token:
        return {"hello": token.preferred_username}
    return {"hello": "guest"}
create_auth_router(prefix: str = '', login: str | None = '/auth/v2/login', callback: str | None = '/auth/v2/callback', token: str | None = '/auth/v2/token', device_flow: str | None = '/auth/v2/device', logout: str | None = '/auth/v2/logout', userinfo: str | None = '/auth/v2/userinfo', jwks: str | None = '/auth/v2/.well-known/jwks.json', tags: List[str | Enum] | None = None) fastapi.APIRouter#

Build an fastapi.APIRouter with standard auth endpoints.

Each route can be disabled by passing None (or "" for token) for the corresponding path.

Broker mode rules

  • broker_mode=True + token=NoneValueError at call time. Clients need the token endpoint to receive broker JWTs.

  • token set + broker_mode=False → logged as a warning. Clients will receive raw IDP tokens without audience restriction.

  • broker_mode=True automatically adds:

    • A broker token endpoint that accepts RFC 8693 token exchange (grant_type=urn:ietf:params:oauth:grant-type:token-exchange), device-code, auth-code and broker refresh flows.

    • A GET jwks endpoint exposing the broker public key.

  • The userinfo endpoint is suppressed in broker mode because the broker JWT is self-contained (preferred_username, email, roles are baked in at mint time).

Parameters:
  • prefix – URL prefix for all routes.

  • login – Login route path.

  • callback – Callback route path.

  • token – Token route path.

  • device_flow – Device flow start route path.

  • logout – Logout route path.

  • userinfo – Userinfo route path.

  • tags – OpenAPI tags for all routes.

Returns:

A router that can be included via app.include_router.

Request examples#

Login

GET /auth/v2/login?redirect_uri=https%3A%2F%2Fapp.example.org%2Fcallback HTTP/1.1
Host: app.example.org

Callback

GET /auth/v2/callback?code=abc&state=xyz HTTP/1.1
Host: app.example.org

Token exchange

POST /auth/v2/token HTTP/1.1
Host: app.example.org
Content-Type: application/x-www-form-urlencoded

code=abc&redirect_uri=https%3A%2F%2Fapp.example.org%2Fcallback

Userinfo

GET /auth/v2/userinfo HTTP/1.1
Host: app.example.org
Authorization: Bearer <access token>