{"record":{"id":"cfa888319ea31863","repo":"passbolt/passbolt_api","slug":"access-restricted-to-administrators-useraccesscontrol","errorCode":null,"errorMessage":"Access restricted to administrators.","messagePattern":"Access restricted to administrators\\.","errorType":"exception","errorClass":"Cake\\Http\\Exception\\ForbiddenException","httpStatus":403,"severity":"warning","filePath":"src/Utility/UserAccessControl.php","lineNumber":151,"sourceCode":"     */\n    public function toArray(): array\n    {\n        return [\n            'userId' => $this->userId,\n            'rolename' => $this->roleName,\n        ];\n    }\n\n    /**\n     * Allow admins only.\n     *\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException\n     * @return void\n     */\n    public function assertIsAdmin(): void\n    {\n        if (!$this->isAdmin()) {\n            throw new ForbiddenException(__('Access restricted to administrators.'));\n        }\n    }\n}\n","sourceCodeStart":133,"sourceCodeEnd":155,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Utility/UserAccessControl.php#L133-L155","documentation":"UserAccessControl::assertIsAdmin() throws Cake's ForbiddenException (HTTP 403) when the encapsulated user's role is not admin. It is a guard used by endpoints/operations reserved for administrators, translating role checks into a standard 403 response.","triggerScenarios":"Any controller/service path calling assertIsAdmin() while the current UserAccessControl was built with a non-admin roleName (e.g. 'User'), such as a regular user calling admin-only endpoints like user deletion or role management.","commonSituations":"Non-admin user hitting admin API routes directly; session/role misconfiguration (UAC built with wrong roleName); tests executing admin operations with a plain-user UAC; frontend showing admin UI to a user whose role was downgraded server-side.","solutions":["This is expected behavior for non-admins: have the client handle the 403 and hide admin functionality for non-admin roles.","Verify the UserAccessControl was constructed with the correct roleName for the authenticated user (role lookup from session/identity).","If the user should be an admin, update their role in the database to admin and re-authenticate."],"exampleFix":"// before\n$this->UserAccessControl->assertIsAdmin(); // 403 for normal users\n// after\nif (!$this->UserAccessControl->isAdmin()) {\n    throw new ForbiddenException(__('This operation is restricted to administrators.'));\n}\n// or in the template/controller: skip admin actions when role !== Role::ADMIN","handlingStrategy":"try-catch","validationCode":"if (!$uac->isAdmin()) {\n    // hide/disable admin operations up front for this role\n    return $this->response->withStatus(403);\n}","typeGuard":"function isAdminUac(UserAccessControl $uac): bool {\n    return $uac->isAdmin();\n}","tryCatchPattern":"try {\n    $uac->assertIsAdmin();\n    $this->doAdminOperation();\n} catch (\\Cake\\Http\\Exception\\ForbiddenException $e) {\n    $this->set('error', __('You are not allowed to perform this operation.'));\n    return $this->response->withStatus(403);\n}","preventionTips":["Gate admin routes in routes/middleware so non-admins never reach admin controllers.","Check role in the client UI to avoid issuing doomed requests.","Keep roleName resolution in one place so UAC is never built with a wrong role."],"tags":["authorization","forbidden","roles","http-403"],"backgroundTag":"insufficient-permissions","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}