{"record":{"id":"7c8c7f2b7e79f3cd","repo":"passbolt/passbolt_api","slug":"could-not-enable-duo-mfa-provider-mfaduoverifyduocodeservice","errorCode":null,"errorMessage":"Could not enable Duo MFA provider.","messagePattern":"Could not enable Duo MFA provider\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoVerifyDuoCodeService.php","lineNumber":58,"sourceCode":"     */\n    protected Client $duoClient;\n\n    /**\n     * MfaDuoVerifyService constructor.\n     *\n     * @param string $authTokenType The authentication token type, which determines which flow this is for\n     * @param \\Duo\\DuoUniversal\\Client|null $client Duo SDK Client\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException If it cannot create the Duo Sdk Client\n     */\n    public function __construct(string $authTokenType, ?Client $client = null)\n    {\n        try {\n            $this->duoClient = $client ?? (new MfaDuoGetSdkClientService())->getOrFail(\n                new MfaOrgSettingsDuoService(MfaOrgSettings::get()->getSettings()),\n                $authTokenType\n            );\n        } catch (Throwable $th) {\n            throw new InternalErrorException(__('Could not enable Duo MFA provider.'), null, $th);\n        }\n    }\n\n    /**\n     * Verify the duo code and retrieve the associated authorization details from Duo.\n     *\n     * @param \\App\\Utility\\UserAccessControl $uac The user access control\n     * @param string $duoCode The duo code\n     * @return bool\n     * @throws \\Cake\\Http\\Exception\\UnauthorizedException If an error occurred while retrieving the Duo authentication details\n     * @throws \\Cake\\Http\\Exception\\UnauthorizedException If the duo authentication origin endpoint (iss) does not match the duo hostname\n     * @throws \\Cake\\Http\\Exception\\UnauthorizedException if the duo authentication subscriber does not match the operator username\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException If Duo doesn't return the authentication details as an array.\n     */\n    public function verify(UserAccessControl $uac, string $duoCode): bool\n    {\n        $operatorUsername = $uac->getUsername();\n        $duoAuthenticationData = $this->requestDuoAuthenticationDetails($duoCode, $operatorUsername);","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoVerifyDuoCodeService.php#L40-L76","documentation":"Thrown in the constructor of MfaDuoVerifyDuoCodeService when the Duo SDK client cannot be obtained. The constructor either uses an injected client or calls MfaOrgSettingsGetSdkClientService::getOrFail(), and any Throwable from that lookup (missing/malformed Duo organization settings, missing credentials) is wrapped in this InternalErrorException.","triggerScenarios":"Instantiating MfaDuoVerifyDuoCodeService without a pre-built client while Duo org settings are absent, incomplete (missing client id/secret/host), or the underlying getOrFail() throws for the given auth token type.","commonSituations":"Duo MFA organization settings were never configured or were deleted; partially saved Duo settings after a failed POST /mfa/policies/duo.json; corrupted org settings JSON in the database.","solutions":["Verify Duo organization settings exist via GET /mfa/policies/duo.json and re-save them if missing.","Check that Duo client id, client secret, and api hostname are all present and non-empty in org settings.","Inspect the previous exception ($th) in logs to identify the root failure from MfaDuoGetSdkClientService.","Run the Duo settings health check endpoint to validate configuration before enabling Duo MFA."],"exampleFix":"// before: constructing with no settings configured\n$service = new MfaDuoVerifyDuoCodeService($uac, $authTokenType);\n// after: guard by checking settings first\n$orgSettings = new MfaOrgSettingsDuoService(MfaOrgSettings::get()->getSettings());\nif (!MfaOrgSettings::get()->isProviderEnabled(MfaSettings::PROVIDER_DUO)) {\n    throw new BadRequestException('Duo provider is not configured.');\n}\n$service = new MfaDuoVerifyDuoCodeService($uac, $authTokenType);","handlingStrategy":"try-catch","validationCode":"$configured = MfaOrgSettings::get()->isProviderEnabled(MfaSettings::PROVIDER_DUO)\n    && !empty(MfaOrgSettings::get()->getSettings()[MfaSettings::PROVIDER_DUO] ?? []);","typeGuard":null,"tryCatchPattern":"try {\n    $service = new MfaDuoVerifyDuoCodeService($uac, $authTokenType);\n} catch (InternalErrorException $e) {\n    Log::error('Duo client init failed: ' . $e->getPrevious()?->getMessage());\n    throw new BadRequestException('Duo MFA is not properly configured.');\n}","preventionTips":["Always complete Duo org settings configuration before enabling the provider.","Run the Duo health-check validation after saving settings.","Log and monitor the wrapped previous exception to detect config drift early."],"tags":["mfa","duo","configuration","internal-error"],"backgroundTag":"missing-config-value","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"}