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​