passbolt/passbolt_api · error · ForbiddenException

Only guests are allowed to proceed with account recovery.

Error message

Only guests are allowed to proceed with account recovery.

What it means

ForbiddenException thrown by AccountRecoveryContinueController::get() when a non-guest (authenticated) user attempts to proceed with account recovery. Only anonymous (GUEST role) users may start the recovery flow.

Solutions

  1. Log out (and clear the session cookie) before using the recovery link
  2. Open the recovery link in a private/incognito window or a different browser profile
  3. Verify SSO settings aren't silently re-authenticating the user
  4. For tests, ensure the fixture sets no authenticated session

Example fix

// before
$this->loginAs('ada@passbolt.test');
$this->get('/account-recovery/continue/...'); // 403
// after
$this->logout();
$this->get('/account-recovery/continue/...'); // 200
Defensive patterns

Strategy: try-catch

Validate before calling

const role = await selfClient.getOwnRole();
if (role !== 'guest') {
  throw new Error('log out before starting account recovery');
}

Try / catch

try {
  await accountRecoveryContinueService.get(userId, tokenId);
} catch (ApiError e) {
  if (e.status === 403 && e.message.includes('Only guests')) {
    await logout();
    retryRecoveryFlow();
  }
}

Prevention

When it happens

Trigger: A logged-in user (admin or user role) opens an account recovery continue link in the same browser session; SSO/cookie auto-login occurring before the recovery flow completes.

Common situations: User clicks a recovery link while already logged in; session cookie from another account persisting; testing recovery while authenticated.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/a5d5455ced2049ae. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Controller/AccountRecoveryContinue/AccountRecoveryContinueController.php:72

     * @return void
     * @throws \Cake\Http\Exception\BadRequestException if the data provided is not valid
     */
    public function get(
        ?string $userId,
        ?string $tokenId,
        AccountRecoveryContinueAggregatorService $accountRecoveryContinueService
    ): void {
        if (!isset($userId) || !Validation::uuid($userId)) {
            throw new BadRequestException(__('The user id is invalid.'));
        }
        if (!isset($tokenId) || !Validation::uuid($tokenId)) {
            throw new BadRequestException(__('The authentication token id is invalid.'));
        }

        if ($this->getRequest()->is('json')) {
            // Do not allow logged in user to recover
            if ($this->User->role() !== Role::GUEST) {
                throw new ForbiddenException(__('Only guests are allowed to proceed with account recovery.'));
            }

            (new AccountRecoveryRequestGetService())->getOrFail($userId, $tokenId);

            $data = $accountRecoveryContinueService->get();

            $this->success(__('The operation was successful.'), $data);
        } else {
            $this->renderHtml();
        }
    }

    /**
     * @return void
     */
    protected function renderHtml(): void
    {
        $this->viewBuilder()

View on GitHub (pinned to 31c1bbc10f)