{"record":{"id":"c01b06c4b72ba5d7","repo":"passbolt/passbolt_api","slug":"the-state-is-required-in-cookie","errorCode":null,"errorMessage":"The state is required in cookie.","messagePattern":"The state is required in cookie\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Controller/AbstractSsoController.php","lineNumber":78,"sourceCode":"        $stateCookie = $this->getStateFromCookie();\n        if ($state !== $stateCookie) {\n            throw new BadRequestException(\n                __('CSRF issue. The state in request data does not match with cookie value.')\n            );\n        }\n\n        return $state;\n    }\n\n    /**\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the state is not provided in cookie or invalid type\n     * @return string state\n     */\n    public function getStateFromCookie(): string\n    {\n        $state = $this->request->getCookie(AbstractSsoService::SSO_STATE_COOKIE);\n        if (!is_string($state) || !SsoState::isValidState($state)) {\n            throw new BadRequestException(__('The state is required in cookie.'));\n        }\n\n        return $state;\n    }\n\n    /**\n     * @return array with error and message\n     */\n    public function assertErrorFromUrlQuery(): ?array\n    {\n        $error = $this->request->getQuery('error');\n        $desc = $this->request->getQuery('error_description');\n\n        if (!is_string($error) || !is_string($desc)) {\n            return null;\n        } else {\n            return [$error => $desc];\n        }","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Controller/AbstractSsoController.php#L60-L96","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function hasSsoStateCookie() { return typeof document.cookie.match(/passbolt_sso_state=([^;]+)/)?.[1] === 'string'; }\nif (!hasSsoStateCookie()) { throw new Error('No SSO state cookie — restart flow with cookies enabled'); }","typeGuard":"function isString(v) { return typeof v === 'string' && v.length > 0; }","tryCatchPattern":"try { await ssoStage2(); } catch (e) { if (e.status === 400 && /state is required in cookie/.test(e.message)) { enableCookies(); clearStaleCookies(); restartFlow(); } else { throw e; } }","preventionTips":["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"],"tags":["sso","cookies","missing-cookie","csrf"],"backgroundTag":"missing-cookie","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}