passbolt/passbolt_api · error · BadRequestException
Unable to verify Duo authentication.
Error message
Unable to verify Duo authentication.
What it means
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.
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)
Example fix
// before
catch (\Exception $e) { /* retry login with same duo code */ }
// after
try { $service->login($uac, $dto, $token); }
catch (BadRequestException $e) { /* restart the whole Duo MFA flow with a fresh token */ } Defensive patterns
Strategy: try-catch
Try / catch
try { $token = $service->login($uac, $dto, $token); } catch (BadRequestException $e) { /* restart Duo MFA flow: duo code is single-use/expired */ log($e->getPrevious()); } Prevention
- Never reuse a duo_code; codes are single-use and short-lived
- Avoid double-submitting the callback form
- Monitor server-to-Duo connectivity
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- A Duo state cookie is required.
- A Duo state cookie is required.
- Unable to verify Duo authentication.
- An authentication token state is required.
- Could not create MFA verified cookie.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/8ee5529f892a7340.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Service/Duo/MfaDuoLoginService.php:94
MfaDuoCallbackDto $duoCallbackDto,
string $token
): AuthenticationToken {
if (!Validation::uuid($token)) {
throw new InvalidArgumentException('The authentication token should be a valid UUID.');
}
$authenticationTokenType = AuthenticationToken::TYPE_MFA_VERIFY;
$authenticationToken = (new MfaDuoCallbackAuthenticationTokenService())
->consumeAndVerifyAuthenticationToken(
$uac,
$authenticationTokenType,
$token,
$duoCallbackDto->state
);
try {
(new MfaDuoVerifyDuoCodeService($authenticationTokenType, $this->duoClient))
->verify($uac, $duoCallbackDto->duoCode);
} catch (Throwable $th) {
throw new BadRequestException(__('Unable to verify Duo authentication.'), null, $th);
}
return $authenticationToken;
}
}
View on GitHub (pinned to 31c1bbc10f)