{"record":{"id":"4e7d86e5a77b4821","repo":"passbolt/passbolt_api","slug":"could-not-enable-duo-mfa-provider","errorCode":null,"errorMessage":"Could not enable Duo MFA provider.","messagePattern":"Could not enable Duo MFA provider\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"critical","filePath":"plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoEnableService.php","lineNumber":60,"sourceCode":"    protected Client $duoClient;\n\n    /**\n     * MfaDuoEnableService constructor.\n     *\n     * @param \\Duo\\DuoUniversal\\Client|null $client Duo SDK Client\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException If it cannot create the Duo Sdk Client\n     */\n    public function __construct(?Client $client = null)\n    {\n        try {\n            $this->duoClient = $client ?? (new MfaDuoGetSdkClientService())->getOrFail(\n                new MfaOrgSettingsDuoService(MfaOrgSettings::get()->getSettings()),\n                AuthenticationToken::TYPE_MFA_SETUP\n            );\n        } catch (Throwable $th) {\n            $msg = __('Could not enable Duo MFA provider.');\n            throw new InternalErrorException($msg, null, $th);\n        }\n    }\n\n    /**\n     * Enable Duo for the operator.\n     *\n     * @param \\App\\Utility\\UserAccessControl $uac The user access control\n     * @param \\Passbolt\\MultiFactorAuthentication\\Model\\Dto\\MfaDuoCallbackDto $duoCallbackDto The Duo callback data\n     * @param string $token The authentication token.\n     * @return \\App\\Model\\Entity\\AuthenticationToken\n     * @throws \\InvalidArgumentException if the provided token is not a UUID\n     * @throws \\Cake\\Http\\Exception\\UnauthorizedException If no active Duo callback authentication can be found.\n     * @throws \\Cake\\Http\\Exception\\UnauthorizedException If the duo state cannot be verified.\n     * @throws \\Cake\\Http\\Exception\\UnauthorizedException If the Duo code cannot be verified.\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException if the Duo provider cannot be enabled for the user.\n     */\n    public function enable(\n        UserAccessControl $uac,","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoEnableService.php#L42-L78","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Check the previous exception to see if it is MfaOrgSettings missing vs DuoException from the SDK","Inject a mock/stub Duo Universal Client in tests and CI so the constructor does not hit real settings","Verify MfaOrgSettings::get() returns Duo settings for the environment (check the mfa org settings database row / file)","Validate the Duo credentials against Duo's admin console — an invalid integration id or secret will fail client construction"],"exampleFix":"// before\nnew MfaDuoEnableService(); // throws if Duo org settings are missing\n// after\ntry {\n    $service = new MfaDuoEnableService();\n} catch (InternalErrorException $e) {\n    // Duo not configured for this instance; surface setup instructions\n    $this->log($e->getPrevious()?->getMessage());\n}","handlingStrategy":"try-catch","validationCode":"$duoSettings = MfaOrgSettings::get()->getSettings();\nif (empty($duoSettings->getClientId()) || empty($duoSettings->getDuoClientSecret()) || empty($duoSettings->getDuoApiHostname())) {\n    throw new \\LogicException('Duo org settings are incomplete; configure MFA Duo first.');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $service = new MfaDuoEnableService();\n} catch (\\Cake\\Http\\Exception\\InternalErrorException $e) {\n    $this->log('Duo client construction failed: ' . $e->getPrevious()?->getMessage());\n    // show 'Duo not configured' guidance to the operator\n}","preventionTips":["Verify Duo org settings exist before any code path instantiates MfaDuoEnableService","Inject a client in tests/CI instead of relying on real org settings","Re-save Duo admin settings after upgrades that change the settings format","Check the previous exception chain to pinpoint the failing setting"],"tags":["configuration","duo","mfa","internal-error","sdk-client"],"backgroundTag":"missing-required-config","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"}