passbolt/passbolt_api · error · BadRequestException

The state is required in cookie.

Error message

The state is required in cookie.

What it means

The SSO flow requires a valid state cookie (AbstractSsoService::SSO_STATE_COOKIE) holding a syntactically valid SsoState. If the cookie is missing, not a string, or fails SsoState::isValidState() validation, the controller cannot anchor the CSRF/state check and throws this 400.

Solutions

  1. Enable cookies for the passbolt domain and restart the SSO flow from stage1 so a fresh state cookie is issued.
  2. Check that requests stay on the same domain/scheme (http vs https, subdomain) that set the cookie — cookie domain/path mismatches are the usual cause.
  3. Clear all passbolt cookies and retry once to rule out a corrupted cookie.
  4. If behind a proxy, verify it forwards Cookie headers and does not rewrite domains.
Defensive patterns

Strategy: validation

Validate before calling

function hasSsoStateCookie() { return typeof document.cookie.match(/passbolt_sso_state=([^;]+)/)?.[1] === 'string'; }
if (!hasSsoStateCookie()) { throw new Error('No SSO state cookie — restart flow with cookies enabled'); }

Type guard

function isString(v) { return typeof v === 'string' && v.length > 0; }

Try / catch

try { await ssoStage2(); } catch (e) { if (e.status === 400 && /state is required in cookie/.test(e.message)) { enableCookies(); clearStaleCookies(); restartFlow(); } else { throw e; } }

Prevention

When it happens

Trigger: Any SSO controller call that calls getStateFromCookie() (state-from-URL or state-from-request-data checks) while the request carries no SSO state cookie or a malformed/expired one.

Common situations: Browser or corporate proxy blocking cookies; user cleared cookies between stage1 and stage2; cookie expired per server TTL; switching between http/https or domains so the cookie is not sent; cookie from an older passbolt version that no longer validates.

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Controller/AbstractSsoController.php:78

        $stateCookie = $this->getStateFromCookie();
        if ($state !== $stateCookie) {
            throw new BadRequestException(
                __('CSRF issue. The state in request data does not match with cookie value.')
            );
        }

        return $state;
    }

    /**
     * @throws \Cake\Http\Exception\BadRequestException if the state is not provided in cookie or invalid type
     * @return string state
     */
    public function getStateFromCookie(): string
    {
        $state = $this->request->getCookie(AbstractSsoService::SSO_STATE_COOKIE);
        if (!is_string($state) || !SsoState::isValidState($state)) {
            throw new BadRequestException(__('The state is required in cookie.'));
        }

        return $state;
    }

    /**
     * @return array with error and message
     */
    public function assertErrorFromUrlQuery(): ?array
    {
        $error = $this->request->getQuery('error');
        $desc = $this->request->getQuery('error_description');

        if (!is_string($error) || !is_string($desc)) {
            return null;
        } else {
            return [$error => $desc];
        }

View on GitHub (pinned to 31c1bbc10f)