Purview
Authorization that speaks SQLAlchemy.
Row-level authorization and tenant isolation for SQLAlchemy 2.0, with a lightweight FastAPI adapter. Write policies as Python functions returning SQLAlchemy predicates. Purview uses those predicates to filter ORM reads and answer explicit permission checks in the database. No policy server or separate language required.
Documentation · Quickstart · API reference · Security boundary
Install
Requires Python 3.11+ and SQLAlchemy 2.0. The distribution is
purview-authz, and the Python import is purview.
# A new or existing uv project
uv add "purview-authz[sqlite]"
# Or use pip in a virtual environment
python -m pip install "purview-authz[sqlite]"
Choose extras for your application:
| Install | Includes |
|---|---|
purview-authz |
Purview and SQLAlchemy's asyncio support |
purview-authz[sqlite] |
Also includes the aiosqlite driver |
purview-authz[postgres] |
Also includes the asyncpg driver |
purview-authz[fastapi,postgres] |
FastAPI adapter and PostgreSQL driver |
One policy, filtered reads
from sqlalchemy import select
from purview import READ, Context, Policy
from purview.sqlalchemy import install
policy = Policy()
@policy.rule(Post, READ)
def read_posts(ctx: Context):
return [Post.author_id == ctx.user_id] if ctx.has_role("author") else []
pv = install(Base, policy, strict=True)
async with sessions() as session:
pv.bind(session, Context(user_id=42, tenant_id=1, roles={"author"}))
posts = (await session.scalars(select(Post))).all()
Here, Base, Post, and sessions are your application's SQLAlchemy models and
async session factory. The tenant predicate and read policy apply together, so this
query returns only posts by author 42 in tenant 1.
Run the complete SQLite quickstart or inspect the runnable script. It creates its own models, database, and sample data.
A registered rule returning [] denies access. The example enables strict=True,
which also denies access to scoped models with no read rule. Without strict mode,
those models are readable throughout the bound tenant.
What Purview handles
- ORM read filtering: selects, database loads through
session.get(), and supported eager or awaitable relationship loads on a bound session. - Tenant checks on object writes: stamp tenant IDs on new objects and reject cross-tenant attachments and tenant changes during normal ORM flushes.
- Explicit authorization:
await pv.authorize(...), batchawait pv.authorized_ids(...), andpv.validate_create(...). - Policy tools: role hierarchies, per-model tenant fields, predicate explanations, and audits for models left readable tenant-wide.
Use a fresh session per actor/request, and bind it before loading application
data. Your app authenticates the actor and resolves trusted tenant membership and
roles. Call authorization helpers before modifying or deleting an object, and call
validate_create() before adding it when you use create rules.
Raw SQL, Core statements, bulk DML, unbound sessions, and explicit bypass blocks are outside automatic enforcement. Global models are exempt from automatic filtering. Purview is an application-layer control, not database row-level security. Read the security boundary before integrating it into request handlers.
Build with Purview
| Guide | Start here for |
|---|---|
| Installation | Drivers, extras, and a clean environment |
| Quickstart | A runnable SQLite example and how it works |
| Writing policies | Grants, defaults, create rules, and tenant configuration |
| FastAPI integration | Request dependencies, explicit checks, and HTTP errors |
| Debugging policies | Explain SQL and audit visibility |
| Migrating from Oso | Map existing policy concepts to Purview |
| Tracker example | FastAPI, Alembic, and PostgreSQL together |
Contribute
git clone https://github.com/jestatsio/purview.git
cd purview
uv sync --locked --all-extras
uv run --locked --all-extras pytest
uv run --locked --all-extras mypy
uv run --locked --all-extras ruff check .
uv run --locked --all-extras mkdocs serve
See Contributing for the development workflow and PostgreSQL tests, Releasing for the release process, and Security for private vulnerability reporting.
MIT licensed. See LICENSE.
Metadata
Release files for purview-authz 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| purview_authz-0.3.1.tar.gz | 194.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| purview_authz-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 228.4 kB
Release files / purview_authz-0.3.1.tar.gz
| Download URL | purview_authz-0.3.1.tar.gz |
|---|---|
| Size | 194.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0dab8859f1e4c1f3daf05671ba2097465f8d70d909c844636a9dadc0351b71d8
|
|
BLAKE2b-256 checksum How to use checksums |
7762f253d33e206bad5ddfd4cc92df1a5702a06678c7094ce5beed892b18f882
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / purview_authz-0.3.1-py3-none-any.whl
| Download URL | purview_authz-0.3.1-py3-none-any.whl |
|---|---|
| Size | 34.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
594f700f97ff76ea422a2cca2640cde638a9e2101d29489e0f2493abcbe6b6c9
|
|
BLAKE2b-256 checksum How to use checksums |
d46fe9e8bc7574f97b27686a587ec4f8577bea19c688914d2aba423279bdd840
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency log