Skip to main content

FastAPI OIDC/OAuth2 middleware and relying-party router, built on py-identity-model

Project description

fastapi-identity-model

OIDC/OAuth2 integration for FastAPI, built on py-identity-model — an OpenID Foundation–certified relying-party library.

It gives you two composable pieces:

Piece Use case
TokenValidationMiddleware + Depends helpers Protect an API / resource server that receives Authorization: Bearer <token>
build_oidc_router Add a browser login flow (authorization code + PKCE) to your app (relying party)

Install

pip install fastapi-identity-model
# with a server for the demo:
pip install "fastapi-identity-model[server]"

Resource server — validate incoming Bearer tokens

from fastapi import FastAPI, Depends
from fastapi_identity_model import (
    TokenValidationMiddleware, OIDCSettings, get_current_user, require_scope,
)

settings = OIDCSettings.from_env()  # OIDC_DISCOVERY_URL, OIDC_CLIENT_ID, OIDC_REDIRECT_URI, ...
app = FastAPI()
app.add_middleware(
    TokenValidationMiddleware,
    discovery_url=settings.discovery_url,
    audience=settings.audience,
    excluded_paths=settings.excluded_paths,
)

@app.get("/api/me")
async def me(user = Depends(get_current_user)):
    return {"sub": user.identity.name, "authenticated": user.identity.is_authenticated}

@app.get("/api/data", dependencies=[Depends(require_scope("api.read"))])
async def data():
    return {"data": "protected"}

The middleware validates the token (signature, issuer, audience, expiry) via py-identity-model and attaches a ClaimsPrincipal to request.state.user. Invalid tokens → 401; an unexpected server-side failure → 500 (never masked as a 401).

Relying party — browser login flow

import os

from fastapi import FastAPI, Request
from starlette.middleware.sessions import SessionMiddleware
from fastapi_identity_model import OIDCSettings, build_oidc_router

settings = OIDCSettings(
    discovery_url="https://api.descope.com/v1/apps/<project_id>/.well-known/openid-configuration",
    client_id="<client_id>",
    redirect_uri="http://localhost:8000/auth/callback",
    scope="openid profile email",
)

app = FastAPI()
# Use a strong secret from the environment — never a committed literal, or
# anyone can forge a session cookie. same_site="lax" is required so the
# provider's redirect back to /auth/callback carries the session cookie.
app.add_middleware(
    SessionMiddleware,
    secret_key=os.environ["SESSION_SECRET"],
    same_site="lax",
    https_only=True,  # behind TLS
)
app.include_router(build_oidc_router(settings), prefix="/auth")

@app.get("/me")
async def me(request: Request):
    return request.session.get("oidc", {})   # {"sub", "claims", "userinfo"} after login

Routes added: GET /auth/login → provider, GET /auth/callback (code exchange, ID-token validation, nonce check, UserInfo sub verification), POST /auth/logout.

Session & security

The router uses Starlette's SessionMiddleware, which signs but does not encrypt the cookie. Stored identity claims are tamper-proof but readable by the client. Raw tokens are stored only when you pass build_oidc_router(settings, store_tokens=True) — enable that only with an encrypted or server-side session store. For production, back the session with a server-side store.

Token refresh

from fastapi_identity_model import TokenManager

tm = TokenManager(discovery_url=..., client_id=..., client_secret=...)
tm.set_tokens(access_token=..., refresh_token=..., expires_in=3600)
access = await tm.get_access_token()   # auto-refreshes shortly before expiry

License

Apache-2.0 — see the repository LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_identity_model-0.1.0.tar.gz (21.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_identity_model-0.1.0-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_identity_model-0.1.0.tar.gz.

File metadata

  • Download URL: fastapi_identity_model-0.1.0.tar.gz
  • Upload date:
  • Size: 21.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fastapi_identity_model-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6ad35d54bc2a0940008b069ac7e92638ac78126af4ca77ecb31c7195575b9fe1
MD5 27ada9af5a7f3db7be8f19e0a058fa2f
BLAKE2b-256 3e7ed15031d7123076341824c91e7a610ed2577b2cdcce46302451bbccfb6953

See more details on using hashes here.

File details

Details for the file fastapi_identity_model-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: fastapi_identity_model-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fastapi_identity_model-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 03a3f0bfbec7accce48bc593d4371367fbe6f3aa68471e15c77c8356b241345a
MD5 75221a9c59b8eb4a038d6d1f636bc0c6
BLAKE2b-256 4894806116e45a98ba8cb9600dfe3b2dc142e3c5cb2d69f7d3eeb12825af8e5d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page