# Flask RLS

> PostgreSQL Row-Level Security (RLS) for multi-tenant Flask applications built on SQLAlchemy. Security is enforced by PostgreSQL itself via native RLS policies, not application-layer query filtering — raw SQL or a forgotten `.filter()` cannot leak another tenant's rows. Context (tenant_id, user_id) is set per transaction via `set_config(..., is_local=true)`, so it is automatically discarded on COMMIT/ROLLBACK and never leaks across pooled connections. Missing or unresolved context fails closed — policies match zero rows, never all rows.

Flask RLS is the Flask/SQLAlchemy sibling of django-rls, created by Kuldeep Pisda. See also fastapi-rls (FastAPI/SQLAlchemy) and django-rls (Django).

## Docs

- [Introduction](https://flask-rls.com/docs/intro/): What RLS is, why Flask RLS enforces it at the database layer, how the extension wires into Flask + SQLAlchemy.
- [Installation](https://flask-rls.com/docs/installation/): Install instructions and supported Python/Flask/SQLAlchemy/PostgreSQL versions.
- [Quick Start](https://flask-rls.com/docs/quick-start/): Four-step walkthrough — initialize the extension, register a TenantPolicy, apply it via Alembic or raw SQL, query normally.
- [Complete Guide](https://flask-rls.com/docs/complete-guide/): End-to-end tutorial — build a multi-tenant Flask app with PostgreSQL RLS from empty project to verified isolation.
- [Architecture Comparison](https://flask-rls.com/docs/architecture/): Row-Level Security vs schema-per-tenant vs database-per-tenant vs application-layer filtering, and when to choose each.
- [Security Model](https://flask-rls.com/docs/security/): The guarantees Flask RLS makes — fail-closed behavior, pool safety, the owner-bypass gotcha — and how each is verified.
- [API Reference](https://flask-rls.com/docs/api-reference/): RLS extension class, Policy classes, SQL generators, PolicyRegistry, Alembic operations, CLI, exceptions.

## Guides

- [Context](https://flask-rls.com/docs/guides/context/): How Flask RLS resolves tenant/user context per request and issues `set_config()` per transaction; `bypass()`/`override()` scopes; fail-closed resolution order.
- [Policies](https://flask-rls.com/docs/guides/policies/): TenantPolicy, UserPolicy, ExpressionPolicy, CustomPolicy; the InitPlan performance pattern; the owner-bypass gotcha.
- [Configuration](https://flask-rls.com/docs/guides/configuration/): GUC naming, requiring context, policy defaults.
- [Testing](https://flask-rls.com/docs/guides/testing/): Testing RLS policies with a non-owner role, driving context in tests, Testcontainers setup.
- [Alembic](https://flask-rls.com/docs/guides/alembic/): Registering RLS operations as first-class Alembic migration steps.
- [Migrating an existing app](https://flask-rls.com/docs/guides/migrating-existing-app/): Incremental adoption path from manual tenant_id filtering to database-enforced RLS, with rollback plan.

## Examples

- [Tenant-based policy](https://flask-rls.com/docs/examples/tenant-based/)
- [User-based policy](https://flask-rls.com/docs/examples/user-based/)
- [Expression policy](https://flask-rls.com/docs/examples/expression-policy/)

## Optional

- [PyPI package](https://pypi.org/project/flask-rls/)
- [GitHub repository](https://github.com/kdpisda/flask-rls)
- [django-rls](https://django-rls.com): Django sibling project
- [fastapi-rls](https://fastapi-rls.com): FastAPI sibling project
