passbolt/passbolt_api · error · BadRequestException

A Duo state cookie is required.

Error message

A Duo state cookie is required.

What it means

Identical guard to error 290 but in DuoVerifyCallbackGetController::consumeAndAssertCookieToken: the Duo state cookie is missing on the MFA verify callback. The cookie set before redirecting to Duo must be returned to prove the callback belongs to the same browser session.

Solutions

  1. Restart the MFA Duo verification flow so the state cookie is set again before the callback.
  2. Enable cookies for the passbolt domain (check SameSite, privacy mode, and blocking extensions).
  3. Do not refresh or re-open the callback URL after it was processed once — the cookie is expired on consumption.
  4. Verify App.fullBaseUrl and the Duo redirect host match so the cookie scope covers the callback.
Defensive patterns

Strategy: validation

Validate before calling

const stateCookie = document.cookie.split('; ').find(c => c.startsWith('passbolt_mfa_duo_state='));
if (!stateCookie) { throw new Error('Duo state cookie missing; restart the Duo verify flow.'); }

Type guard

function hasDuoStateCookie(request): boolean {
  return typeof request.cookies?.passbolt_mfa_duo_state === 'string';
}

Try / catch

try {
  await duoVerifyCallback();
} catch (e) {
  if (e.status === 400 && /Duo state cookie is required/.test(e.message)) {
    restartDuoVerifyFlow(); // cookie missing/expired: redo redirect to Duo
  } else { throw e; }
}

Prevention

When it happens

Trigger: GET /mfa/duo/verify/callback without the passbolt_mfa_duo_state cookie: cookies blocked or stripped, callback opened directly/bookmarked, new browser session, or the cookie already consumed by an earlier callback attempt.

Common situations: Third-party cookie blocking during the Duo redirect; SameSite attribute conflicts; privacy extensions deleting cookies; user refreshing the callback after the cookie was expired/consumed on first hit.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/0b6d4de3c6b84213. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Controller/Duo/DuoVerifyCallbackGetController.php:180

            throw new FormValidationException($msg, $mfaDuoCallbackForm);
        }

        return $mfaDuoCallbackDto;
    }

    /**
     * Consume the duo state cookie containing the user authentication token id and assert the format this one.
     *
     * @return string The token id stored in the cookie
     * @throws \Cake\Http\Exception\BadRequestException if the cookie is not defined
     * @throws \Cake\Http\Exception\BadRequestException if the cookie value is not a string
     * @throws \Cake\Http\Exception\BadRequestException if the cookie value is not a valid uuid
     */
    private function consumeAndAssertCookieToken(): string
    {
        $cookieToken = (new MfaDuoStateCookieService())->readDuoStateCookieValue($this->getRequest());
        if (is_null($cookieToken)) {
            throw new BadRequestException(__('A Duo state cookie is required.'));
        }
        $cookieToExpire = new Cookie(MfaDuoStateCookieService::MFA_COOKIE_DUO_STATE);
        $this->setResponse($this->getResponse()->withExpiredCookie($cookieToExpire));

        if (!is_string($cookieToken)) {
            throw new BadRequestException(__('The Duo state cookie value should be a string.'));
        } elseif (!Validation::uuid($cookieToken)) {
            throw new BadRequestException(__('The Duo state cookie should be a valid UUID.'));
        }

        return $cookieToken;
    }

    /**
     * Add to the response the MFA verified cookie.
     *
     * @param \App\Utility\UserAccessControl $uac User access control
     * @param \App\Authenticator\SessionIdentificationServiceInterface $sessionIdentificationService session ID service

View on GitHub (pinned to 31c1bbc10f)