passbolt/passbolt_api · error · ForbiddenException

You are not allowed to access this location.

Error message

You are not allowed to access this location.

What it means

The MFA user-settings DELETE endpoint throws a ForbiddenException in `beforeFilter` when the requesting user is not allowed to manage MFA settings for the targeted `userId`. `isAllowed()` only permits an admin or the user deleting their own settings.

Solutions

  1. Ensure the userId route parameter matches the authenticated user, or authenticate as an admin
  2. Check the user's role in the response of GET /users.json (role.name === 'admin')
  3. Log in again if the session expired
  4. If an admin still gets 403, verify the route parameter placeholder name matches `userId`

Example fix

// before
await fetch(`/mfa/user/settings/${targetUserId}.json`, {method:'DELETE'});
// after (guard client-side too)
if (isAdmin || targetUserId === loggedInUserId) {
  await fetch(`/mfa/user/settings/${targetUserId}.json`, {method:'DELETE'});
}
Defensive patterns

Strategy: validation

Validate before calling

const canDelete = (me, targetUserId) => me.role?.name === 'admin' || me.id === targetUserId;
if (!canDelete(currentUser, userId)) throw new Error('Not allowed to delete MFA settings for this user');

Type guard

null

Try / catch

try { await deleteMfaUserSettings(userId); } catch (e) {
  if (e.response?.status === 403) notify('Only admins or the owner can delete MFA settings');
}

Prevention

When it happens

Trigger: A non-admin user calling DELETE /mfa/user/settings/<anotherUserUuid>.json; an anonymous request with no userId in the route; a logged-in user whose role is 'user' targeting anyone but themselves.

Common situations: Frontend sending the wrong user id in the URL (e.g. logged-in user id vs. target id swapped); missing admin role because the user's account was downgraded; calling the endpoint while the session has expired so `$this->User` is anonymous.

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/fbbddb427c1d823c. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Controller/UserSettings/MfaUserSettingsDeleteController.php:56

    /**
     * @return void
     */
    public function initialize(): void
    {
        parent::initialize();

        $this->Users = $this->fetchTable('Users');
    }

    /**
     * @inheritDoc
     */
    public function beforeFilter(EventInterface $event)
    {
        $userId = $this->getRequest()->getParam('userId', null);

        if (!$this->isAllowed($userId)) {
            throw new ForbiddenException(__('You are not allowed to access this location.'));
        }

        parent::beforeFilter($event);
    }

    /**
     * @param string|null $userId UUID of the user for which MFA config must be deleted
     * @return void
     */
    public function delete(?string $userId = null)
    {
        if (!Validation::uuid($userId)) {
            throw new BadRequestException(__('The user id is not valid.'));
        }

        try {
            /** @var \App\Model\Entity\User $user */
            $user = $this->Users->findView($userId, $this->User->role())->find('locale')->firstOrFail();

View on GitHub (pinned to 31c1bbc10f)