6.2 Authorization Helpers
KMP builds on CakePHP Authorization with tenant-local roles, permissions, active windows, warrants, and branch scopes. Use the public authorization APIs; policy internals such as _hasPolicy() and _getBranchIdsForPolicy() are for policy implementations, not controllers.
Common controller patterns
// One entity
$this->Authorization->authorize($entity, 'edit');
// Collection/controller action
$this->Authorization->authorizeModel('index');
// Scope before pagination, grid data, counts, or export
$query = $this->Authorization->applyScope($query, 'index');
Follow the exact call shape already used by the relevant app controller base; API and web controllers have different surrounding response behavior.
Identity helpers
KmpIdentityInterface is implemented by member and service-principal identities. It exposes identifiers, permissions, policy data, and scope application. Member adds these useful helpers:
| Helper | Contract |
|---|---|
getPermissions() / getPermissionIDs() |
Cached effective tenant permissions |
getPolicies(branchIds?) |
Policy configuration, optionally narrowed by branch |
isSuperUser() |
Whether an effective permission carries the super-user flag |
getBranchIdsForAction(action, resource) |
null for global, an ID array for scoped access, [] for none |
canManageMember(member) |
Current self/parent-minor management rule |
getBranchIdsForAction() accepts an entity/table resource or a Cake alias such as Gatherings or Waivers.GatheringWaivers. It is useful when a service needs branch IDs to build an already-authorized domain query. Do not treat null as no access—it means global access.
Policy behavior
BasePolicy maps standard canAdd, canEdit, canDelete, canView, canIndex, and canGridData to configured policy grants. scopeIndex() uses the table’s addBranchScopeQuery() when branch-limited; canGridData() defaults to index authorization. Subclasses add domain actions and custom scopes.
Super users short-circuit in BasePolicy::before(). URL/controller resources are handled through configured URL policy methods. Do not call the protected policy helpers from application code or copy the deny sentinel used internally by policy scopes.
AuthorizationService::checkCan() is a boolean helper for nested/non-terminal checks and preserves Cake’s “authorization checked” state. Normal controller actions should still call authorize() so a missing check is detectable.
Scope is mandatory
Authorizing index proves the identity may use the endpoint; it does not necessarily constrain every row. Apply scope to the actual query used by pagination, Dataverse, CSV/PDF/JSON, autocomplete, counts, and related-record pickers. Never authorize one query and serialize another.
Tenancy and caching
Permission/policy loaders resolve data from the active tenant and cache it. Do not reuse an identity after changing tenant context. Clear existing identity/permission caches through established lifecycle paths when grants change or impersonation starts/stops.
Tests
Cover allow, deny, global scope, one/multiple branch scopes, no policy, super user, active-window/warrant edges, self/parent-minor rules where applicable, collection row exclusion, exports/API variants, service-principal behavior, impersonation, and two tenants with colliding IDs.