passbolt/passbolt_api · error · BadRequestException

The Duo state cookie should be a valid UUID.

Error message

The Duo state cookie should be a valid UUID.

What it means

Thrown by DuoSetupCallbackGetController::consumeAndAssertCookieToken when the Duo state cookie value is a string but fails Cake's Validation::uuid() check. The state token is generated as a UUID and must round-trip unchanged; any corruption or forgery is rejected.

Solutions

  1. Clear the MFA Duo cookies and restart the Duo setup flow to get a fresh UUID state cookie.
  2. Check no proxy or middleware truncates or encodes the Cookie header.
  3. Do not manually set or edit passbolt MFA cookies; let the server generate them.
  4. If reproducible, verify Validation::uuid() format expectations against the cookie value logged in the request.
Defensive patterns

Strategy: validation

Validate before calling

const uuidRe = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (!uuidRe.test(cookies.passbolt_mfa_duo_state ?? '')) { throw new Error('Duo state cookie is not a valid UUID; restart flow.'); }

Type guard

function isValidUuid(value: unknown): value is string {
  return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
}

Try / catch

try {
  await callbackDuoSetup();
} catch (e) {
  if (e.status === 400 && /valid UUID/.test(e.message)) {
    clearMfaCookies(); restartDuoSetupFlow();
  } else { throw e; }
}

Prevention

When it happens

Trigger: GET /mfa/duo/setup/callback with a state cookie containing a non-UUID string: truncated value, URL-encoded/decoded variant, hand-crafted value, or value from an unrelated cookie.

Common situations: Cookie truncated by intermediary proxies with header size limits; manual cookie manipulation during debugging; copy-pasted callback URLs with altered cookie values; old cookies left from a differently formatted flow.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Controller/Duo/DuoSetupCallbackGetController.php:196

     *
     * @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
     * @return void
     * @throws \Cake\Http\Exception\InternalErrorException if it cannot create MFA cookie
     */
    private function addMfaVerifiedCookieToResponse(
        UserAccessControl $uac,
        SessionIdentificationServiceInterface $sessionIdentificationService
    ): void {
        try {

View on GitHub (pinned to 31c1bbc10f)