{"record":{"id":"7520595d64a0b328","repo":"passbolt/passbolt_api","slug":"this-authentication-provider-is-already-setup-disable-it","errorCode":null,"errorMessage":"This authentication provider is already setup. Disable it first","messagePattern":"This authentication provider is already setup\\. Disable it first","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/MultiFactorAuthentication/src/Controller/MfaSetupController.php","lineNumber":41,"sourceCode":"\nabstract class MfaSetupController extends MfaController\n{\n    /**\n     * Fail is account is already setup for this authentication provider\n     *\n     * @param string $provider name of the provider\n     * @throws \\Cake\\Http\\Exception\\BadRequestException\n     * @return bool\n     */\n    protected function _notAlreadySetupOrFail(string $provider)\n    {\n        if ($this->mfaSettings->getAccountSettings() !== null) {\n            $isReadyToUse = $this->mfaSettings\n                ->getAccountSettings()\n                ->isProviderReady($provider);\n            if ($isReadyToUse) {\n                $msg = __('This authentication provider is already setup. Disable it first');\n                throw new BadRequestException($msg);\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Handle get request when ready to use settings are present\n     *\n     * @param string $provider name of the provider\n     * @return void\n     */\n    protected function _handleGetExistingSettings(string $provider)\n    {\n        $verified = $this->mfaSettings\n            ->getAccountSettings()\n            ->getVerifiedFrozenTime($provider);\n        $this->success(__('Multi Factor Authentication is configured!'), ['verified' => $verified]);","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/MultiFactorAuthentication/src/Controller/MfaSetupController.php#L23-L59","documentation":"Thrown during MFA provider setup when the user already has a fully configured and ready-to-use account setting for that provider. _notAlreadySetupOrFail refuses to re-run setup for an active provider to prevent overwriting an existing valid configuration.","triggerScenarios":"GET/POST to /mfa/setup/<provider> when mfaSettings->getAccountSettings()->isProviderReady($provider) returns true (e.g. totp already provisioned with a verified secret).","commonSituations":"Re-scanning a QR code for totp that is already active; retrying setup after a partially completed flow that actually saved settings; stale client state believing setup is incomplete.","solutions":["Disable the provider first (DELETE /mfa/setup/<provider>) then re-run setup","Use the existing provider configuration instead of setting it up again","If the stored setting is broken, disable and re-enable the provider"],"exampleFix":"// before: POST /mfa/setup/totp.json (fails if already ready)\nawait http.delete('/mfa/setup/totp.json'); // disable first\nawait http.post('/mfa/setup/totp.json', data); // then set up","handlingStrategy":"validation","validationCode":"const settings = await getAccountMfaSettings();\nif (settings?.providers?.includes(provider)) throw new Error(`Provider ${provider} already set up; disable first`);","typeGuard":null,"tryCatchPattern":"try { await mfaSetup(provider); } catch (e) { if (/already setup/.test(e.message)) await disableProvider(provider); }","preventionTips":["Query current MFA account settings before invoking setup","Surface a 'disable first' step in setup UIs","Handle partial setup flows idempotently"],"tags":["mfa","setup","conflict","http-400"],"backgroundTag":"invalid-state-transition","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}