Skip to main content

Introduction

Flask RLS brings PostgreSQL Row-Level Security (RLS) to Flask applications backed by SQLAlchemy. Security is enforced by the database, not by application-layer query filtering โ€” so even raw SQL or a forgotten .filter() cannot leak another tenant's rows.

Flask RLS is the Flask/SQLAlchemy sibling of django-rls, created by Kuldeep Pisda. The concepts and naming mirror django-rls, adapted to SQLAlchemy Core and the Flask request lifecycle.

What is Row-Level Security?โ€‹

Row-Level Security is a PostgreSQL feature that filters rows automatically based on policies you define on a table. When a query runs, PostgreSQL evaluates each policy's predicate and returns only the rows the current session is authorized to see. The application cannot bypass it by "forgetting" a filter โ€” the rule lives in the database.

Why Flask RLS?โ€‹

  • ๐Ÿ”’ Database-level security โ€” enforced by PostgreSQL with FORCE ROW LEVEL SECURITY.
  • ๐Ÿข Tenant & user policies โ€” TenantPolicy, UserPolicy, CustomPolicy, and the Pythonic ExpressionPolicy.
  • โšก Pool-safe context โ€” set per transaction via set_config('rls.*', โ€ฆ, true), so it cannot leak across pooled connections.
  • ๐Ÿงฉ ORM-agnostic โ€” binds at the SQLAlchemy engine layer; works with bare SQLAlchemy or Flask-SQLAlchemy.
  • ๐Ÿงฑ Alembic operations โ€” manage policies as first-class migration steps.
  • ๐Ÿงช Proven against PostgreSQL โ€” isolation and fail-closed behavior are verified against a live database.

How it worksโ€‹

  1. Define policies with TenantPolicy / UserPolicy / ExpressionPolicy.
  2. Apply them to your tables (via Alembic operations or generated SQL).
  3. Initialize the extension and set g.tenant_id / g.user_id per request.

On every transaction, Flask RLS reads the current context and issues set_config('rls.tenant_id', โ€ฆ, true) so your policies filter automatically.

from flask_rls import RLS, TenantPolicy

rls = RLS(app, engine=db.engine)
rls.register("invoices", TenantPolicy("tenant_isolation", "tenant_id"))

Ready to try it? Head to the Quick Start.