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

  1. 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
  2. Check server-to-Duo connectivity and API credentials in the MFA org settings
  3. Inspect the chained previous exception to distinguish expired/reused code from a network failure
  4. 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

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.

Related errors


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)