Skip to content

busykoala/fastapi-opa

Repository files navigation

Open Policy Agent (OPA) middleware for FastAPI

Table of contents

fastapi-opa adds authentication and authorization middleware to FastAPI. It handles the login flow with an identity provider, validates the returned token, and forwards the user's claims to Open Policy Agent for policy-based access control.

Flow Diagram

Every request passes through the middleware. Unauthenticated requests redirect to the identity provider. Once OPA validates the token, it evaluates the request against your policy and either allows or rejects it with a 403.

uv add fastapi-opa

Optional extras:

Extra Adds
graphql GraphQLInjectable for GraphQL payload enrichment
saml SAML 2.0 authentication support
authlib Authlib-backed PKCE token generation (stdlib fallback used otherwise)
uv add "fastapi-opa[graphql,saml]"

For SAML, you may need to install the binary dependencies without wheels:

PIP_NO_BINARY="lxml,xmlsec" uv run pip install --force-reinstall --no-binary=lxml --no-binary=xmlsec lxml xmlsec

💡 see docs/getting-started.md for a complete local setup with Keycloak and OPA, including Docker Compose configuration and a working policy.

Add the middleware to your FastAPI app:

from fastapi import FastAPI

from fastapi_opa import OPAConfig
from fastapi_opa.auth import OIDCAuthentication
from fastapi_opa.auth import OIDCConfig
from fastapi_opa.models import TokenCookieConfig
from fastapi_opa.opa.cookie_middleware import CookieAuthMiddleware

oidc_config = OIDCConfig(
    well_known_endpoint="https://idp.example.com/realms/myrealm/.well-known/openid-configuration",
    app_uri="https://app.example.com",
    client_id="my-client",
    client_secret="my-secret",
    preserve_tokens=True,  # required for CookieAuthMiddleware
)
oidc_auth = OIDCAuthentication(oidc_config)
opa_config = OPAConfig(authentication=oidc_auth, opa_host="http://localhost:8181")

app = FastAPI()
app.add_middleware(
    CookieAuthMiddleware,
    config=opa_config,
    cookie_config=TokenCookieConfig(cookie_secure=True),
)


@app.get("/finance/salary/{name}")
async def salary(name: str) -> dict[str, str]:
    return {"msg": "success", "name": name}

Introduction and tutorials

Doc Description
docs/getting-started.md Full local setup with Keycloak and OPA: Docker Compose, Rego policy, Keycloak configuration

Open Policy Agent

Doc Description
docs/opa.md OPA input format, policy examples, OPAConfig reference, skipping endpoints, body buffering
docs/token-enrichment.md Custom injectables and GraphQL enrichment to add extra fields to the OPA input

Authentication

Doc Description
docs/authentication.md All authentication methods: API key, OIDC (full configuration reference), SAML, custom handlers
docs/cookie-auth.md Cookie-based sessions with CookieAuthMiddleware: flow, TokenCookieConfig options, security checklist
docs/pkce.md Public clients and PKCE: setup, PKCEStoreProtocol, example Redis store for multi-process deployments

See CONTRIBUTING.md for the full contributor guide. In brief:

# Install all dev dependencies
uv sync

# Full QA pipeline: lint, type check, tests, security scan
make qa

# Tests only
uv run pytest

# Tests against the lowest allowed dependency versions
make qa-lowest

Thanks to all the contributors below. Furthermore thanks for raising issues.

About

Fastapi OPA middleware incl. auth flow.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors

Languages