sapl-fastapi
Policy-based authorization for FastAPI. Write access control rules as external SAPL policy files and enforce them at runtime through decorators like @pre_enforce and @post_enforce. Policies can be updated without code changes or redeployment.
Built on sapl-base and the SAPL 4.1 enforcement model: planner-driven constraint handling, the SUSPEND decision verb, an optional RSocket transport, and transaction rollback on post-write denial. Data-layer query rewriting is available via sapl-sqlalchemy (SQL) and sapl-pymongo (MongoDB).
How It Works
Your application decorates endpoints with enforcement decorators. SAPL intercepts the call, sends an authorization subscription to the Policy Decision Point (PDP), and enforces the decision, including any obligations or advice the policy attaches.
@app.get("/patient/{patient_id}")
@pre_enforce(action="read", resource="patient")
async def get_patient(request: Request, patient_id: str):
return {"id": patient_id, "name": "Jane Doe", "ssn": "123-45-6789"}
policy "permit doctors to read patient data"
permit
action == "read";
"DOCTOR" in subject.roles
If the PDP permits, the endpoint runs. If not, HTTP 403 is returned. If the decision carries obligations (like access logging or field redaction), they are enforced automatically through registered constraint handlers.
What You Get
SAPL goes beyond simple permit/deny. Decisions can carry obligations that must be fulfilled, advice that should be attempted, and resource transformations that modify return values before they reach the caller. The library handles all of this transparently.
For SSE endpoints, the single stream_enforce decorator maintains a live connection to the PDP, so access rights update in real time as policies, attributes, or the environment change. Built-in constraint handlers cover JSON field redaction and collection filtering. Writing custom handlers follows a simple registration pattern with register_provider.
Database Transactions
If you configure a transaction provider, a denial that lands after the endpoint has written to the database rolls the transaction back. Three triggers cause a rollback: a post_enforce DENY, a post_enforce output-obligation failure, and a pre_enforce output-obligation failure (the pre-decision permits, but its output obligations run after the method writes). A clean permit commits. It is opt-in: with no provider set, the PEP owns no transaction.
With an async SQLAlchemy session, pass session.begin() directly:
from sapl_fastapi.dependencies import set_transaction_provider
set_transaction_provider(lambda: get_current_session().begin())
The factory should resolve the current request's session, for example a request-scoped AsyncSession held in a contextvar. For a sync session or transaction.atomic, wrap it with from_sync_context from sapl_base.pep.
Getting Started
pip install sapl-fastapi
from contextlib import asynccontextmanager
from fastapi import FastAPI
from sapl_fastapi import SaplConfig
from sapl_fastapi.dependencies import configure_sapl, cleanup_sapl
@asynccontextmanager
async def lifespan(app: FastAPI):
configure_sapl(SaplConfig(base_url="https://localhost:8443"))
yield
await cleanup_sapl()
app = FastAPI(lifespan=lifespan)
For setup instructions, configuration options, the constraint handler reference, and the full API, see the FastAPI documentation.
Links
License
Apache-2.0
Metadata
Release files for sapl-fastapi 4.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sapl_fastapi-4.1.0.tar.gz | 15.9 kB | Without provenance | Details for sapl_fastapi-4.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| sapl_fastapi-4.1.0-py3-none-any.whl | Python 3 | none | any | Details for sapl_fastapi-4.1.0-py3-none-any.whl |
Total release size: 24.2 kB
Release files / sapl_fastapi-4.1.0.tar.gz
| Download URL | sapl_fastapi-4.1.0.tar.gz |
|---|---|
| Size | 15.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dacfd496fc9fa6de9cf238eb772ea977e8f3e0f1727547fbfef1057d0b94fcb0
|
|
BLAKE2b-256 checksum How to use checksums |
69316bf12766c7ab2cc5801e0011f2b800ec2c8c67fdd2c78c6ac82e1254e577
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Release files / sapl_fastapi-4.1.0-py3-none-any.whl
| Download URL | sapl_fastapi-4.1.0-py3-none-any.whl |
|---|---|
| Size | 8.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0dd4dd51a339f7b91718d5f3845335cff226ea23eb1ffcaac3d50b46508c5f83
|
|
BLAKE2b-256 checksum How to use checksums |
bc4df886e1121d7fed99ab9db0e6fba9601c5194adab2595d831400419b17a07
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Security for sapl-fastapi 4.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.