Many breaches happen because authorization is only enforced in the application layer.
If a developer ships one endpoint with a missing tenant filter, you get cross-tenant exposure.
Data-layer authorization reduces that risk by enforcing access closer to the data.
Common approaches
Row-Level Security (RLS)
Databases like Postgres can enforce policies such as:
tenant_id = current_setting('app.tenant_id')- user must be a member of the org
Pros: strong guardrails.
Cons: requires careful session/context handling and good observability.
Query constraints / predicate injection
Enforce constraints in a shared query layer:
- always add
WHERE tenant_id = ? - add
AND resource_id IN (...)for authorized resources
Design tips
- Treat “tenant id” as a first-class security boundary.
- Make “no tenant context” fail closed.
- Log both the authorization decision and the query predicate used.
Pitfalls
- RLS without good debugging tooling (developers hate opaque denies).
- Forgetting background jobs and ETL paths.
- Mixing multiple tenant concepts (account vs org vs workspace) without clarity.
Where to go next
- /topic/authorization/multi-tenant-saas-authorization
- /category/identity-security
- IDPro Book of Knowledge (reference): https://bok.idpro.org/
