Skip to main content

Access control at a glance

Four layers, evaluated independently

OrderLayerDecidesA denial looks like
1Tenant isolationWhich rows exist at all404 — the row is invisible
2PermissionsWhether the action is allowed403, with the missing code named
3ABAC policiesWhether this record is visible403 directly, or dropped from a list
4Field maskingWhether this value is visibleThe value is masked; the record returns

None assumes another did its job. The innermost is enforced by the database.

Why the denials differ

A 404 across tenants is not obfuscation — the row is genuinely invisible to the query, so nothing looked and refused. A 403 would confirm it exists somewhere.

A policy denial inside a list drops the row rather than erroring, for the same reason: erroring reveals that something exists and is withheld.

Composing access

permission codes → role → group → user
└───────────→ user (direct)

Effective permissions are the union of every role held directly and through groups. Bind through groups so access follows joining and leaving.

ABAC policies

Deny-overrides on a default-allow base: a denial always wins, and ordering is never a decision input.

A denial with no conditions is refused when you save it — it would match every request and lock the tenant out of the screen needed to remove it. Access-control administration is exempt from ABAC policies for the same reason.

Masking

Applied when the response is generated, not per endpoint. That is what makes it unbypassable: no alternative surface returns the value unmasked, including for the AI layer.

Actor metadata in audit entries is never masked — withhold the audit permission instead.

Verify with the account

Effective permissions are a union across roles and groups. Reading a role definition tells you what one role grants, not what a person can do. Sign in as them.

Next


Last verified against commit 1e1de1ad (2026-08-03)