Policies that look correct.
Row-level security is the right place to enforce access, because it's the one layer an application bug can't route around. Its failure modes are quiet, though: a policy that is subtly too permissive looks exactly like a correct one, right up until someone reads another tenant's data. These are the ones worth knowing about.
Written with AI assistance, from real audits of a real codebase. Every policy and test in these guides was run against real Postgres before publishing, and the harness that runs them is free and open source.
An insert policy that checks user_id = auth.uid() and never constrains
organization_id. It reads correctly out loud, and it hands over an
entire tenant in one statement.
Owner, admin, member — with the tenant as a required argument, so a policy that forgets it won't compile. Plus every escalation path between the ranks, and why some denials raise while others are silent.
Four holes in the policy everyone reaches for first, and the
security definer function that closes them — claiming in one
statement, refusing unverified email, and never becoming an enumeration oracle.
How "you may share what you can see" turns every recipient into a distributor, and how one expression reused across four policies lets a view-only grant quietly permit writes.
Authenticate, authorise, validate, act — in that order, because the moment an operation moves into a function, row-level security stops running. Plus the two defaults that turn a helper into a privilege escalation.
Test your own policies, not just read about mine
Every guide here ends with assertions worth writing. rls-test-harness
is the thing that runs them: real Postgres, as a real user, with the
auth.uid() path your app actually uses. It matters that it runs as a
non-superuser, because postgres bypasses row-level security entirely and
a suite that connects as the owner passes no matter how broken the policy is.
No Docker, no cloud project, one dependency. Point it at your schema and a full run takes about three seconds. MIT licensed.
Get it on GitHub See the worked example