Test what must be denied An authorization test suite should prove that allowed users can act and disallowed users cannot read or change the resource. Many...
Test what must be denied
An authorization test suite should prove that allowed users can act and disallowed users cannot read or change the resource. Many applications test only the happy path. The missing cases are often cross tenant IDs, a role with partial permissions, a revoked membership, and a direct API call that bypasses the UI.
Build a small matrix of roles, resource ownership, resource state, and actions. For an invoice approval route, include a manager from the same tenant, a manager from another tenant, a viewer, a suspended manager, and an invoice already approved.
Assert response and side effects
A 403 response is not enough if the controller already changed the record before checking a policy. Assert the database row, audit event, queued job, and external call state as appropriate. For an unauthorized read, confirm the response does not reveal the title or private fields.
Use the same authentication middleware and route that production uses. Calling a policy method directly tests policy logic but does not prove the controller invokes it.
Cover more than detail pages
Test search suggestions, exports, file downloads, bulk updates, and nested relationships. These paths can leak data even when the main show route is protected. If a list is tenant scoped, create two tenants with overlapping IDs or similar titles and assert the result contains only authorized rows.
Handle exceptional administrators
If a platform administrator can cross tenant boundaries, test that path separately and verify audit logging. An ordinary organization admin should not inherit platform privileges because the role labels look similar.
Keep fixtures realistic
Factories should create membership and ownership explicitly. A test that always assigns one tenant to every record cannot reveal cross tenant mistakes. Test after a role change and during queued work when authorization may be checked at a later time.
Include a direct request with a forged resource ID and a valid session. Test both reading and writing, because a controller can correctly hide a record in the index while still accepting a guessed ID in an update route. For bulk operations, mix an allowed ID with a forbidden ID and verify the whole request follows the documented atomicity rule. A partial success must never be silent.
If the application caches permissions, test revocation after the cache is populated. The expected delay before a revoked role loses access should be explicit and appropriate to the risk of the action.
Conclusion
Authorization testing is a matrix of actions and boundaries. The most valuable assertion is that a forbidden request leaves no private data or partial side effect. See web and SaaS development for the broader design.
References