passbolt/passbolt_api · error · UnauthorizedException

The duo authentication subscriber does not match the…

Error message

The duo authentication subscriber does not match the operator username.

What it means

Thrown by assertDuoAuthenticationSubscriber() when the security setting passbolt.security.mfa.duo.verifySubscriber is true and the Duo-authenticated subscriber differs from the passbolt operator username. This ensures the person who authenticated with Duo is the logged-in passbolt user.

Solutions

  1. Align the user's Duo username with their passbolt username, or vice versa.
  2. If divergent usernames are intentional policy-wise, set passbolt.security.mfa.duo.verifySubscriber to false in config (security trade-off).
  3. Check for case/whitespace differences in both systems' usernames.
  4. Confirm the user authenticated with their own Duo account, not a shared one.

Example fix

// before: config mismatched by design
'passbolt' => ['security' => ['mfa' => ['duo' => ['verifySubscriber' => true]]]]
// after (if usernames legitimately differ)
'verifySubscriber' => false
Defensive patterns

Strategy: validation

Validate before calling

// pre-check alignment outside the flow
$matches = mb_strtolower($duoSubscriber) === mb_strtolower($operatorUsername);
if (!$matches && Configure::read('passbolt.security.mfa.duo.verifySubscriber')) {
    // fail fast with a user-facing message
}

Try / catch

try {
    $service->verify($uac, $mfaToken, $duoCode);
} catch (UnauthorizedException $e) {
    $this->logSecurityEvent('duo_subscriber_mismatch', $uac);
    throw $e;
}

Prevention

When it happens

Trigger: Verifying a duo code when the Duo username differs from the passbolt username (case-insensitively) while verifySubscriber is enabled.

Common situations: User's Duo account uses a different email/username than passbolt; admin renamed a user in one system but not the other; company policy enables verifySubscriber but account names were never aligned.

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

Appendix: source

Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoVerifyDuoCodeService.php:143

            throw new UnauthorizedException($msg);
        }
    }

    /**
     * Assert that the Duo subscriber who authenticated matches the user's username.
     *
     * @see https://duo.com/docs/oauthapi
     * @param string $duoSubscriber Duo subscriber from callback
     * @param string $operatorUsername Operator username
     * @return void
     * @throws \Cake\Http\Exception\UnauthorizedException if the duo authentication subscriber does not match the operator username
     */
    private function assertDuoAuthenticationSubscriber(string $duoSubscriber, string $operatorUsername): void
    {
        $verifySubscriber = Configure::read(self::PASSBOLT_SECURITY_MFA_DUO_VERIFY_SUBSCRIBER);
        if ($verifySubscriber === true && mb_strtolower($duoSubscriber) !== mb_strtolower($operatorUsername)) {
            $msg = __('The duo authentication subscriber does not match the operator username.');
            throw new UnauthorizedException($msg);
        }
    }
}

View on GitHub (pinned to 31c1bbc10f)