{"record":{"id":"4f7c1f9a9665473f","repo":"passbolt/passbolt_api","slug":"this-operation-is-not-allowed-for-this-user-4f7c1f","errorCode":null,"errorMessage":"This operation is not allowed for this user.","messagePattern":"This operation is not allowed for this user\\.","errorType":"exception","errorClass":"Cake\\Http\\Exception\\ForbiddenException","httpStatus":403,"severity":"error","filePath":"src/Controller/Users/UsersIndexController.php","lineNumber":139,"sourceCode":"        $this->success(__('The operation was successful.'), $users);\n    }\n\n    /**\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException if user doesn't have access to the resource requested by the filter\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if multiple has-access filters are requested\n     * @param array $options from\n     * @return void\n     */\n    public function assertHasAccess(array $options): void\n    {\n        if (isset($options['filter']['has-access']) && count($options['filter']['has-access'])) {\n            if (count($options['filter']['has-access']) > 1) {\n                throw new BadRequestException(__('Multiple has-access filters are not supported.'));\n            }\n            $resourceId = $options['filter']['has-access'][0];\n            $service = new UserHasPermissionService();\n            if (!$service->check(PermissionsTable::RESOURCE_ACO, $resourceId, $this->User->id())) {\n                throw new ForbiddenException(__('This operation is not allowed for this user.'));\n            }\n        }\n    }\n}\n","sourceCodeStart":121,"sourceCodeEnd":144,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Users/UsersIndexController.php#L121-L144","documentation":"UsersIndexController::assertHasAccess throws this ForbiddenException when the authenticated user requests GET /users.json?filter=has-access=<resourceId> but UserHasPermissionService::check determines the user has no permission entry on that resource. The has-access filter restricts the user index to users sharing access to a given resource, so a caller without access to that resource is denied entirely.","triggerScenarios":"GET /users.json?filter=has-access=<resource-id> where (a) the resource id is valid but the authenticated user has no permission (no user/owner/read/update share) on it, (b) the resource id belongs to a deleted resource, or (c) the user passes another user's resource id they do not share.","commonSituations":"Clients building resource-sharing UIs with a stale or mistyped resource id; a user whose permission on the resource was just revoked while their session/UI still references it; API scripts iterating resources where some are no longer shared with them; tests using a fixture resource id belonging to another user.","solutions":["Verify the authenticated user actually has a permission row on the resource (check the permissions table for aco_foreign_key = resourceId and aro_foreign_key = userId) before calling the endpoint.","First fetch the resources the user can access via GET /resources.json and use one of those ids in the has-access filter.","Re-check the resource id: it must be a valid existing resource UUID; a deleted resource yields no permission match.","If the user should have access, grant them a permission on the resource (share endpoint) or log in as a user with access."],"exampleFix":"// before\nawait fetch('/users.json?filter=has-access=' + staleResourceId);\n// after\nconst resources = (await fetch('/resources.json')).body;\nif (resources.some(r => r.id === resourceId)) {\n  await fetch('/users.json?filter=has-access=' + resourceId);\n}","handlingStrategy":"try-catch","validationCode":"// before calling, ensure user shares the resource\nconst resources = await api.get('/resources.json?contain[permissions]=1');\nif (!resources.some(r => r.id === resourceId)) {\n  throw new Error(`User has no access to resource ${resourceId}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const users = await api.get(`/users.json?filter=has-access=${resourceId}`);\n} catch (e) {\n  if (e.status === 403 && /not allowed for this user/.test(e.message)) {\n    // fall back to resources the user does have access to\n  }\n}","preventionTips":["Resolve resource ids from GET /resources.json rather than hardcoding them.","Check the permissions table/UI that the user shares the resource before querying has-access.","Handle revocation gracefully: a permission removed elsewhere can invalidate previously working filters."],"tags":["http-403","permissions","api","authorization"],"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"}