{"record":{"id":"d25c94537fad5e7f","repo":"passbolt/passbolt_api","slug":"the-state-is-required-in-url-parameters","errorCode":null,"errorMessage":"The state is required in URL parameters.","messagePattern":"The state is required in URL parameters\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Controller/AbstractSsoController.php","lineNumber":136,"sourceCode":"    public function getTokenFromUrlQuery(): string\n    {\n        $token = $this->request->getQuery('token');\n        if (!is_string($token) || !OAuthTokenValidation::token($token)) {\n            throw new BadRequestException(__('The token is required in URL parameters.'));\n        }\n\n        return $token;\n    }\n\n    /**\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the state is not provided in URL query\n     * @return string state\n     */\n    public function getStateFromUrlQuery(): string\n    {\n        $state = $this->request->getQuery('state');\n        if (!is_string($state) || !SsoState::isValidState($state)) {\n            throw new BadRequestException(__('The state is required in URL parameters.'));\n        }\n\n        return $state;\n    }\n\n    /**\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the code (access token) is not provided in URL query\n     * @return string code\n     */\n    public function getCodeFromUrlQuery(): string\n    {\n        $code = $this->request->getQuery('code');\n        if (!isset($code) || !is_string($code)) {\n            throw new BadRequestException(__('The code is required in URL parameters.'));\n        }\n\n        return $code;\n    }","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Controller/AbstractSsoController.php#L118-L154","documentation":"The SSO callback requires a 'state' query parameter that must pass SsoState::isValidState(). If it is absent, not a string, or structurally invalid, the controller cannot proceed with the CSRF check and throws this 400.","triggerScenarios":"GET to an SSO callback endpoint without ?state=... or with a malformed state value, typically when the identity provider does not echo back the state parameter it was given.","commonSituations":"Misconfigured OAuth2 provider (state not passed through on redirect); URL-encoding stripping/corrupting the state; users editing or shortening the callback URL; provider appending parameters in a way that mangles the query string.","solutions":["Compare the redirect URL the provider sent against the one passbolt generated in stage1 — the state must be echoed verbatim.","Fix the provider app configuration so the full callback URL (including state) is preserved on redirect.","Restart the SSO flow to get a fresh state; do not hand-craft the callback URL.","Check for middleware/proxy rewriting or decoding the query string (e.g. double URL-decoding corrupts the state)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const state = new URL(callbackUrl).searchParams.get('state');\nif (typeof state !== 'string' || state.length === 0) { throw new Error('Provider did not echo back the state parameter'); }","typeGuard":"function hasStateParam(url) { const s = new URL(url).searchParams.get('state'); return typeof s === 'string' && s.length > 0; }","tryCatchPattern":"try { await ssoCallback(url); } catch (e) { if (e.status === 400 && /state is required in URL/.test(e.message)) { checkProviderStateEcho(); restartFlow(); } else { throw e; } }","preventionTips":["Ensure the IdP app passes through the state parameter on redirect","Do not modify or truncate the callback URL","Watch for middleware double-decoding the query string"],"tags":["sso","missing-parameter","state-validation","url"],"backgroundTag":"missing-query-parameter","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"}