passbolt/passbolt_api · critical · InternalErrorException

Could not enable Duo MFA provider.

Error message

Could not enable Duo MFA provider.

What it means

The MfaDuoEnableService constructor must build a Duo Universal SDK client. When no client is injected, it calls MfaDuoGetSdkClientService::getOrFail using the organization's Duo settings; any Throwable during that construction (missing org settings, Duo SDK init failure, network/credential errors surfacing as DuoException) is wrapped in this InternalErrorException. Because it throws in the constructor, the service cannot even be instantiated when Duo is not correctly configured.

Solutions

  1. Configure the Duo organization settings (client id, client secret, API hostname) via the admin MFA settings screen or config/mfa.php before enabling Duo per user
  2. Check the previous exception to see if it is MfaOrgSettings missing vs DuoException from the SDK
  3. Inject a mock/stub Duo Universal Client in tests and CI so the constructor does not hit real settings
  4. Verify MfaOrgSettings::get() returns Duo settings for the environment (check the mfa org settings database row / file)
  5. Validate the Duo credentials against Duo's admin console — an invalid integration id or secret will fail client construction

Example fix

// before
new MfaDuoEnableService(); // throws if Duo org settings are missing
// after
try {
    $service = new MfaDuoEnableService();
} catch (InternalErrorException $e) {
    // Duo not configured for this instance; surface setup instructions
    $this->log($e->getPrevious()?->getMessage());
}
Defensive patterns

Strategy: try-catch

Validate before calling

$duoSettings = MfaOrgSettings::get()->getSettings();
if (empty($duoSettings->getClientId()) || empty($duoSettings->getDuoClientSecret()) || empty($duoSettings->getDuoApiHostname())) {
    throw new \LogicException('Duo org settings are incomplete; configure MFA Duo first.');
}

Try / catch

try {
    $service = new MfaDuoEnableService();
} catch (\Cake\Http\Exception\InternalErrorException $e) {
    $this->log('Duo client construction failed: ' . $e->getPrevious()?->getMessage());
    // show 'Duo not configured' guidance to the operator
}

Prevention

When it happens

Trigger: Instantiating MfaDuoEnableService (directly or via the controller/dependency injection) when the Duo organization settings are absent or malformed (missing client id/secret/api hostname), or the Duo SDK Client constructor rejects them.

Common situations: Duo provider not configured on the instance (admin never saved Duo org settings); partial config after a failed settings save; running in an environment without Duo credentials (CI/tests); Duo settings corrupted after a migration or manual database edit.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — 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/4e7d86e5a77b4821. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoEnableService.php:60

    protected Client $duoClient;

    /**
     * MfaDuoEnableService constructor.
     *
     * @param \Duo\DuoUniversal\Client|null $client Duo SDK Client
     * @return void
     * @throws \Cake\Http\Exception\InternalErrorException If it cannot create the Duo Sdk Client
     */
    public function __construct(?Client $client = null)
    {
        try {
            $this->duoClient = $client ?? (new MfaDuoGetSdkClientService())->getOrFail(
                new MfaOrgSettingsDuoService(MfaOrgSettings::get()->getSettings()),
                AuthenticationToken::TYPE_MFA_SETUP
            );
        } catch (Throwable $th) {
            $msg = __('Could not enable Duo MFA provider.');
            throw new InternalErrorException($msg, null, $th);
        }
    }

    /**
     * Enable Duo for the operator.
     *
     * @param \App\Utility\UserAccessControl $uac The user access control
     * @param \Passbolt\MultiFactorAuthentication\Model\Dto\MfaDuoCallbackDto $duoCallbackDto The Duo callback data
     * @param string $token The authentication token.
     * @return \App\Model\Entity\AuthenticationToken
     * @throws \InvalidArgumentException if the provided token is not a UUID
     * @throws \Cake\Http\Exception\UnauthorizedException If no active Duo callback authentication can be found.
     * @throws \Cake\Http\Exception\UnauthorizedException If the duo state cannot be verified.
     * @throws \Cake\Http\Exception\UnauthorizedException If the Duo code cannot be verified.
     * @throws \Cake\Http\Exception\InternalErrorException if the Duo provider cannot be enabled for the user.
     */
    public function enable(
        UserAccessControl $uac,

View on GitHub (pinned to 31c1bbc10f)