Skip to main content

FastAPI-Topaz

PyPI Python Version License Downloads

FastAPI-Topaz asks a Topaz authorizer whether each request may proceed, and returns HTTP 403 Forbidden when the answer is no.

Full documentation: jmanteau.github.io/fastapi-topaz

Upgrading from 1.x? See Upgrading to 2.0.

How it works

Your FastAPI app sends the user's identity and the route to Topaz. Topaz evaluates a policy and returns allowed or denied.

flowchart LR
    C[Client] --> F[FastAPI route]
    F --> D["Dependency<br/>or TopazMiddleware"]
    D --> TC[TopazConfig]
    TC -->|"gRPC"| T[Topaz authorizer]
    T --> P["Policies (Rego)"]
    T --> R["Directory (relationships)"]
    TC -.->|"denied"| X[HTTP 403]
Component Role Source
TopazConfig Holds the Topaz connection, how to find the user, and the policy root. Create it once at startup. config.py L153–L243
Dependencies Protect one route at a time with Depends(...). dependencies.py
TopazMiddleware Protects every route in the app, except the paths you exclude. middleware.py L131–L186

Requirements

  • Python 3.10 or later
  • FastAPI 0.100 or later (except 0.137.0 and 0.137.1)
  • A running Topaz instance

Install

pip install fastapi-topaz

Quick start

This example protects GET /documents. Topaz evaluates the policy myapp.GET.documents for the user in request.state.user_id.

from fastapi import Depends, FastAPI, Request
from fastapi_topaz import (
    AuthorizerOptions,
    Identity,
    IdentityType,
    TopazConfig,
    require_policy_allowed,
)

config = TopazConfig(
    authorizer_options=AuthorizerOptions(url="localhost:8282"),
    policy_path_root="myapp",
    identity_provider=lambda req: Identity(
        type=IdentityType.IDENTITY_TYPE_SUB,
        value=req.state.user_id,
    ),
    policy_instance_name="myapp",
)

app = FastAPI()

@app.get("/documents")
async def list_documents(
    request: Request,
    _: None = Depends(require_policy_allowed(config, "myapp.GET.documents")),
):
    return {"documents": [...]}

Choose a check

Pick the check that matches your question. Not sure which one? Read Choosing an authorization approach.

Question to answer Use Source
May this user call this route? (you name the policy) require_policy_allowed() dependencies.py L137–L169
May this user call this route? (policy name built from the route) require_policy_auto() dependencies.py L172–L232
Does this user have a relation to this object, such as can_write on a document? require_rebac_allowed() dependencies.py L235–L305
Does this user have access at every level of a nested path, such as org → project → document? require_rebac_hierarchy() dependencies.py L497
Fetch one object, and return it only if the user may see it get_authorized_resource() dependencies.py L308
Keep only the objects in a list that the user may see filter_authorized_resources() dependencies.py L413
Protect every route without editing each one TopazMiddleware middleware.py L131

require_policy_auto() builds the policy name from the HTTP method and the route template:

Route Policy name
GET /documents myapp.GET.documents
GET /documents/{id} myapp.GET.documents.__id
PUT /users/{user_id}/docs/{doc_id} myapp.PUT.users.__user_id.docs.__doc_id

Example of a relationship check: the user must have the can_write relation on the document whose ID is in the {id} path parameter.

@app.put("/documents/{id}")
async def update_document(
    id: int,
    _: None = Depends(require_rebac_allowed(config, "document", "can_write")),
):
    ...

Production features

Turn each feature on by passing an object to TopazConfig. All are optional.

Feature What it does TopazConfig argument Guide
Decision cache Reuses recent decisions for a set Time To Live (TTL), so Topaz gets fewer calls. decision_cache Reference
Circuit breaker Stops calling Topaz after repeated failures, then falls back to cached decisions. circuit_breaker Circuit breaker
Audit logging Writes each decision as a structured JSON log line. audit_logger Audit logging
Metrics Exports Prometheus metrics. metrics Observability
Tracing Exports OpenTelemetry (OTel) traces. tracing Observability
Test doubles Replaces Topaz with fixed rules in unit tests. — (fastapi_topaz.testing) Testing

Command-line tool

The package installs a fastapi-topaz command. Each subcommand reads your app from module:attribute.

Command What it does
generate-policies Writes a Rego policy skeleton for each route.
policy-diff Lists routes that have no policy, and policies that match no route.
generate-rights-matrix Writes a Markdown table of routes and their policies.
policy-map Prints which policy each route uses.
check Shows which policy a given request URL resolves to. Add --live to ask Topaz for the decision.
fastapi-topaz policy-diff --app myapp.main:app --policies policies/

Full options: CLI reference. Source: cli.py L329.

Terms

Term Meaning
Policy A rule, written in Rego, that Topaz evaluates to return allowed or denied.
Rego The policy language of Open Policy Agent (OPA), which Topaz uses.
ReBAC Relationship-Based Access Control. Access depends on how the user relates to an object, for example "owner of document 42".
gRPC The remote procedure call protocol this library uses to talk to Topaz (default port 8282).
Identity provider Your function that reads the current user from the request.

Documentation

The documentation follows the Diátaxis framework.

Section Read it when you want to…
Tutorials learn step by step, from zero
How-to guides solve one specific problem
Reference look up an exact function, argument, or CLI option
Explanation understand the design and the concepts

Related: Topaz documentation · FastAPI documentation

License

Apache 2.0

Metadata

Release files for fastapi-topaz 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastapi-topaz 2.0.0
File Size Uploaded
fastapi_topaz-2.0.0.tar.gz 182.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fastapi-topaz 2.0.0
File Interpreter ABI Platform
fastapi_topaz-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 244.2 kB

Release files / fastapi_topaz-2.0.0.tar.gz

Download URL fastapi_topaz-2.0.0.tar.gz
Size 182.2 kB
Tags Source
SHA-256 checksum
How to use checksums
2446cd45c5c146df75f05482112179ef5597df74999a8fa35733a57ceb916040
BLAKE2b-256 checksum
How to use checksums
feafc62d9ed66dd655d1e3c8c42f7ed0c74398ead5b2cd0e5ebdd4c58033926d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.12

Release files / fastapi_topaz-2.0.0-py3-none-any.whl

Download URL fastapi_topaz-2.0.0-py3-none-any.whl
Size 62.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c4e6f5a4306e0f61b738762a613a3117410761ef00c19a82bc968a14978bb19c
BLAKE2b-256 checksum
How to use checksums
75011c12d79cfe9ccb0fd53a81acc6fb418b4c290579f7fe2b2908e4fc204067
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0

2 release files

0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page