Define actions and resources
List meaningful actions such as invoice.read, invoice.review, and invoice.approve. Distinguish reading a summary from exporting a dataset or performing a financial action. Model the resource attributes needed for each decision, including tenant, business unit, classification, state, and ownership.
Use roles to group stable responsibilities, then apply attributes or relationships for context. An approver role does not necessarily authorize every invoice in every region. Default to denial when required context is missing, and record which trusted system provides each attribute. User supplied request fields cannot establish their own authority.
Evaluate the complete policy at execution
For invoice approval, require an active identity, tenant membership, an approver role, a permitted business unit, and an amount within the actor's approved limit. Separation of duties may also prevent the submitter from approving their own record. These are policy choices that must be confirmed with the business owner.
Evaluate permissions on the server for every protected operation, including bulk actions, exports, background jobs, and alternate API routes. Hiding a button improves usability but is not an access control. Recheck mutable resource state when executing the action so a prior UI decision does not become stale authorization.
| Condition | Trusted input | Failure result |
|---|---|---|
| Active identity | Identity or session service | Deny access |
| Tenant membership | Membership store | Deny resource access |
| Approval authority | Role and policy attributes | Deny action |
| Current invoice state | Authoritative resource | Require renewed review |
Treat policy as a versioned system
Keep policy definitions reviewable and assign owners. A policy change can affect many routes and jobs, so test its impact using representative decision requests before activation. Include a policy version in decision telemetry to make an access regression traceable without logging sensitive resource content.
Cache authorization results only within a defined validity model. Revocation, resource reassignment, and tenant switching must invalidate or bypass stale decisions. An outage of the policy service needs explicit behavior. High risk writes should not become permitted because a dependency failed; any limited fallback must be intentionally designed and audited.
Test denied access
Build a matrix of actors, actions, resources, and expected decisions. Include guessed identifiers, cross tenant resource references, stale roles, suspended accounts, missing attributes, and bulk requests containing one unauthorized item. Test through the external interface so middleware and resource lookup behavior are included.
Check that denial responses do not leak whether another tenant's resource exists. Preserve useful internal diagnostics under restricted access. Review privileged support and emergency access separately, with time bounds and accountability. A clear explanation of why access is denied helps operations without weakening the boundary that caused the denial.