{"record":{"id":"61bd8b0a3c631756","repo":"passbolt/passbolt_api","slug":"only-guests-are-allowed-to-create-an-account-recovery","errorCode":null,"errorMessage":"Only guests are allowed to create an account recovery request.","messagePattern":"Only guests are allowed to create an account recovery request\\.","errorType":"http","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"plugins/PassboltEe/AccountRecovery/src/Controller/AccountRecoveryRequests/AccountRecoveryRequestsCreateController.php","lineNumber":52,"sourceCode":"     */\n    public function beforeFilter(EventInterface $event)\n    {\n        $this->Authentication->allowUnauthenticated(['create']);\n\n        parent::beforeFilter($event);\n    }\n\n    /**\n     * Creates an account recovery request\n     * Sends an email to the requesting user and the admins on success\n     *\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the data provided is not valid\n     */\n    public function create(): void\n    {\n        if ($this->User->role() !== Role::GUEST) {\n            throw new ForbiddenException(__('Only guests are allowed to create an account recovery request.'));\n        }\n\n        $data = $this->getRequest()->getData();\n        if (!isset($data) || !is_array($data) || empty($data)) {\n            throw new BadRequestException(__('Invalid request. Please provide the required data.'));\n        }\n\n        $request = (new AccountRecoveryRequestCreateService())->create($data);\n\n        $this->success(__('The operation was successful.'), $request);\n    }\n}\n","sourceCodeStart":34,"sourceCodeEnd":65,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/AccountRecovery/src/Controller/AccountRecoveryRequests/AccountRecoveryRequestsCreateController.php#L34-L65","documentation":"Role guard in the account recovery request create action: although the action is unauthenticated, only users with the GUEST role (logged-out users with a valid recovery token context) may file a recovery request; any logged-in role gets a 403.","triggerScenarios":"POST /account-recovery/requests.json while logged in as admin or user role; auto-login/SSO session present when creating the request.","commonSituations":"Recovering an account while still logged in with another account; leftover session cookie; test suite authenticating the request unintentionally.","solutions":["Log out and clear session cookies before initiating recovery","Send the request without authentication credentials (no Authorization header/cookie)","Open recovery flow in a private window for manual testing","In tests, do not attach an authenticated session to the create call"],"exampleFix":"// before\n$this->authenticateAs('ada');\n$this->post('/account-recovery/requests.json', $data); // 403\n// after\n$this->post('/account-recovery/requests.json', $data); // guest request, 200","handlingStrategy":"try-catch","validationCode":"const auth = getStoredAuth();\nif (auth && auth.role !== 'guest') {\n  await logout(); // recovery requests require guest role\n}","typeGuard":null,"tryCatchPattern":"try {\n  await accountRecoveryRequestService.create(payload);\n} catch (ApiError e) {\n  if (e.status === 403 && e.message.includes('Only guests')) {\n    await logout();\n    retryCreate();\n  }\n}","preventionTips":["Never send auth cookies/headers with recovery request creation","Log out fully before initiating recovery for the current account","Disable SSO auto-login for the recovery route during testing","Keep guest-only endpoints out of authenticated API clients"],"tags":["php","cakephp","authorization","guest-only"],"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"}