Row Level Security, explained for people who are not DBAs
Multi-tenant apps usually protect your data with application code. Tenon asks the database to do it. Here is what that means and why it matters when a bug ships.
Every multi-tenant application makes the same promise: your data is separate from everyone else's. The interesting question is who enforces it. In most SaaS products, the answer is "the application code". In Tenon, the answer is "the database". This piece explains the difference without assuming you've ever written SQL.
The usual way: a very important "if"
Imagine a shared spreadsheet with a column called Organization. Every customer's rows are in the same sheet. When Acme logs in, the app is supposed to show only rows where Organization = Acme. It does this by adding a filter to every single query:
SELECT * FROM tickets WHERE org_id = 'acme' AND ...
That works right up until someone writes a query and forgets the filter. Or a URL accepts a ticket ID and the code checks that the ticket exists but not that it belongs to you. Or a new feature reuses an old function that was never meant to be called with another tenant's ID. These are not exotic attacks. They're Tuesday bugs, and they've been behind a long list of real-world data exposures, because the entire security model rests on every developer remembering an if.
The Tenon way: the database says no
Postgres has a feature called Row Level Security (RLS). It lets you attach a rule (a policy) directly to a table. Once enabled, the database applies that rule to every query that touches the table, no matter who wrote the query or what they forgot.
Simplified, Tenon's policy on the tickets table says:
create policy "tickets: org members only" on tickets
for all using (
org_id = auth.current_org_id()
or auth.is_superadmin()
);
In English: a row is visible only if it belongs to the organization the current user is signed into, or if the user is a superadmin. That rule is attached to the table itself. If a developer writes SELECT * FROM tickets with no filter at all, Postgres quietly returns only the caller's rows. The bug can't leak, because the filter isn't in the app. It's in the data.
The application asks. The database decides.
Why "every table" matters
RLS is only as good as its coverage. A tool that enables it on the obvious tables (tickets, pages) but forgets attachments, reactions, poll votes or webhook logs has a gap exactly where nobody is looking. Tenon enables RLS on every table with org-scoped policies, and it ships a self-test that tries to read and write across tenants and reports that every attempt was denied. You run it after every deploy; the output is audit evidence.
What about the AI?
Here's a pleasant side effect. Because the rule lives in the database, it applies to everything that reads the database, including the Brain assistant. When you ask Brain "what's stuck?", it queries with your permissions and sees only your organization's tickets. There's no separate "AI permission model" to get wrong.
What about superadmins?
Someone has to administer a multi-tenant deployment. Tenon has an explicit superadmin role that the policies recognise. It's a deliberate, visible exception, not a backdoor, and actions taken with it are logged. The point is that cross-tenant access is a named capability you can audit, not a side effect of a missing filter.
Is RLS slow?
Not in practice. The policy becomes part of the query plan, and with an index on org_id (which Tenon has) it's a cheap filter Postgres is very good at. The overhead is far smaller than the cost of a breach postmortem.
The takeaway for non-DBAs
- Most multi-tenant apps rely on application code to keep tenants apart. That's fragile.
- Row Level Security moves the rule into the database, where a forgotten
ifcan't undo it.
- Coverage matters: every table, plus a way to prove it.
- It applies to AI too, which is the only sane way to give an assistant access to your work.
If you're evaluating any multi-tenant tool, Tenon or otherwise, "who enforces isolation, and how would I check?" is the best question you can ask. Here's our answer.