{"record":{"id":"7033f2bb8a2b6ffa","repo":"passbolt/passbolt_api","slug":"you-are-not-authorized-to-edit-the-role","errorCode":null,"errorMessage":"You are not authorized to edit the role.","messagePattern":"You are not authorized to edit the role\\.","errorType":"exception","errorClass":"Cake\\Http\\Exception\\ForbiddenException","httpStatus":403,"severity":"error","filePath":"src/Controller/Users/UsersEditController.php","lineNumber":154,"sourceCode":"        $this->success(__('The user has been updated successfully.'), $user);\n    }\n\n    /**\n     * Validate if the user is authorized to edit the data\n     *\n     * @param array $data user data\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException if the user is not admin or not editing themselves\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException if the user is not admin and editing role\n     */\n    protected function assertCanEdit(array $data): void\n    {\n        // Admin can edit all users, other users can only edit themselves\n        if ($this->User->role() !== Role::ADMIN && $data['id'] !== $this->User->id()) {\n            throw new ForbiddenException(__('You are not authorized to access that location.'));\n        }\n        if ($this->User->role() !== Role::ADMIN && (isset($data['role']) || isset($data['role_id']))) {\n            throw new ForbiddenException(__('You are not authorized to edit the role.'));\n        }\n    }\n\n    /**\n     * Validate the data coming from the request\n     *\n     * @param array $data user data\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if gpgkey is sent (v2 only)\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if groups data is sent (v2 only)\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if data is not provided or invalid\n     */\n    protected function assertRequestData(array $data): void\n    {\n        if (empty($data) || count($data) < 2) {\n            throw new BadRequestException(__('Some user data should be provided.'));\n        }\n        if (isset($data['gpgkey'])) {","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Users/UsersEditController.php#L136-L172","documentation":"ForbiddenException (HTTP 403) from assertCanEdit: a non-admin user included `role` or `role_id` in the edit payload. Role management is admin-only, so any self-edit that attempts to alter the role is rejected even when editing one's own record.","triggerScenarios":"PUT /users/{id}.json with `role_id` (or `role`) present in the body while authenticated as a non-admin — including a user editing themselves and echoing back the full entity including role_id.","commonSituations":"Clients that serialize the entire fetched user object (including role_id) back on update instead of sending only changed fields; scripts attempting self-promotion to admin.","solutions":["Remove `role`/`role_id` from the payload; send only the fields you intend to change.","If a role change is genuinely needed, perform it as an admin account.","Patch client code to strip server-managed fields (role, role_id) before sending updates."],"exampleFix":"// before\nawait api.editUser(id, { ...user, profile: updatedProfile }); // includes role_id\n// after\nconst { role, role_id, ...payload } = user;\nawait api.editUser(id, { ...payload, profile: updatedProfile });","handlingStrategy":"type-guard","validationCode":"function stripRoleFields(data) { const { role, role_id, ...rest } = data; return rest; }","typeGuard":"function hasRoleFields(data) { return 'role' in data || 'role_id' in data; }\nif (hasRoleFields(payload) && session.role !== 'admin') payload = stripRoleFields(payload);","tryCatchPattern":"try { await api.editUser(id, data); } catch (e) { if (e.code === 403 && /edit the role/.test(e.message)) { data = stripRoleFields(data); return api.editUser(id, data); } throw e; }","preventionTips":["Always send a minimal diff, never the full fetched entity.","Strip server-managed fields (role, role_id) from update payloads in client code.","Perform role changes through admin-only workflows."],"tags":["authorization","role-management","http-403","users"],"backgroundTag":"permission-denied","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"}