{"record":{"id":"8ee5529f892a7340","repo":"passbolt/passbolt_api","slug":"unable-to-verify-duo-authentication-mfaduologinservice","errorCode":null,"errorMessage":"Unable to verify Duo authentication.","messagePattern":"Unable to verify Duo authentication\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoLoginService.php","lineNumber":94,"sourceCode":"        MfaDuoCallbackDto $duoCallbackDto,\n        string $token\n    ): AuthenticationToken {\n        if (!Validation::uuid($token)) {\n            throw new InvalidArgumentException('The authentication token should be a valid UUID.');\n        }\n        $authenticationTokenType = AuthenticationToken::TYPE_MFA_VERIFY;\n        $authenticationToken = (new MfaDuoCallbackAuthenticationTokenService())\n            ->consumeAndVerifyAuthenticationToken(\n                $uac,\n                $authenticationTokenType,\n                $token,\n                $duoCallbackDto->state\n            );\n        try {\n            (new MfaDuoVerifyDuoCodeService($authenticationTokenType, $this->duoClient))\n                ->verify($uac, $duoCallbackDto->duoCode);\n        } catch (Throwable $th) {\n            throw new BadRequestException(__('Unable to verify Duo authentication.'), null, $th);\n        }\n\n        return $authenticationToken;\n    }\n}\n","sourceCodeStart":76,"sourceCodeEnd":100,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoLoginService.php#L76-L100","documentation":"During Duo login, the Duo code presented in the callback is verified against Duo via MfaDuoVerifyDuoCodeService. Any failure of that verification (invalid/expired duo_code, Duo API error, client failure) is converted into a BadRequestException('Unable to verify Duo authentication.') with the original exception chained.","triggerScenarios":"Calling MfaDuoLoginService::login() with a duoCode that Duo rejects — expired, already used (Duo codes are single-use), replayed, or a Duo network/API failure during verification.","commonSituations":"User double-submits the Duo callback (code already consumed), the Duo state/cookie flow was tampered with, clock skew or long delay makes the short-lived code expire, or the server cannot reach Duo.","solutions":["Restart the MFA flow: generate a new mfa_verify token and a fresh Duo authentication URL, then complete login once with the new duo_code","Check server-to-Duo connectivity and API credentials in the MFA org settings","Inspect the chained previous exception to distinguish expired/reused code from a network failure","Prevent duplicate callback submissions in the client (disable button after first callback)"],"exampleFix":"// before\ncatch (\\Exception $e) { /* retry login with same duo code */ }\n// after\ntry { $service->login($uac, $dto, $token); }\ncatch (BadRequestException $e) { /* restart the whole Duo MFA flow with a fresh token */ }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { $token = $service->login($uac, $dto, $token); } catch (BadRequestException $e) { /* restart Duo MFA flow: duo code is single-use/expired */ log($e->getPrevious()); }","preventionTips":["Never reuse a duo_code; codes are single-use and short-lived","Avoid double-submitting the callback form","Monitor server-to-Duo connectivity"],"tags":["mfa","duo","verification","bad-request"],"backgroundTag":"http-error-response","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"}