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
- Enable cookies for the passbolt domain and restart the SSO flow from stage1 so a fresh state cookie is issued.
- 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.
- Clear all passbolt cookies and retry once to rule out a corrupted cookie.
- 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
- Enable cookies for the passbolt domain before starting SSO
- Stay on the same domain/scheme that set the cookie (http vs https)
- Avoid clearing cookies mid-flow
- Verify proxies forward Cookie headers unchanged
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
- CSRF issue. The state in URL and Cookies do not match.
- CSRF issue. The state in request data does not match with…
- Single sign-on failed. Invalid nonce.
- The SSO state is invalid.
- The SSO state type is invalid.
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)