{"record":{"id":"8ee678b9fb40836f","repo":"passbolt/passbolt_api","slug":"the-sso-state-is-invalid","errorCode":null,"errorMessage":"The SSO state is invalid.","messagePattern":"The SSO state is invalid\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Service/SsoStates/SsoStatesAssertService.php","lineNumber":89,"sourceCode":"\n        $this->consume($ssoState);\n    }\n\n    /**\n     * Makes assertions against the SSO state entity, current user, and settings ID.\n     * This is used to ensure data integrity between request user/client, settings.\n     *\n     * @param \\Passbolt\\Sso\\Model\\Entity\\SsoState $ssoState SSO state entity.\n     * @param string $ssoSettingsId SSO Settings ID.\n     * @param \\App\\Utility\\ExtendedUserAccessControl $uac UAC object.\n     * @return void\n     */\n    private function assert(SsoState $ssoState, string $ssoSettingsId, ExtendedUserAccessControl $uac): void\n    {\n        $errorMsg = __('The SSO state is invalid.') . ' ';\n\n        if (!SsoState::isValidState($ssoState->state)) {\n            throw new BadRequestException(trim($errorMsg));\n        }\n\n        if ($ssoState->isExpired()) {\n            throw new BadRequestException($errorMsg . __('The SSO state is expired.'));\n        }\n\n        if ($ssoState->user_id !== $uac->getId() || !Validation::uuid($ssoState->user_id)) {\n            throw new BadRequestException($errorMsg . __('User id mismatch.'));\n        }\n\n        if (Configure::read('passbolt.security.userIp')) {\n            if ($ssoState->ip !== $uac->getUserIp()) {\n                throw new BadRequestException($errorMsg . __('User IP mismatch.'));\n            }\n        }\n\n        if (Configure::read('passbolt.security.userAgent')) {\n            if ($ssoState->user_agent !== $uac->getUserAgent()) {","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Service/SsoStates/SsoStatesAssertService.php#L71-L107","documentation":"Thrown by SsoStatesAssertService::assert when the state value stored in the SSO state record does not pass SsoState::isValidState(). The state links the browser's SSO redirect to a pending authentication attempt; an unrecognized state value means the record is corrupt or not a genuine state entry.","triggerScenarios":"Completing the SSO return flow with a state cookie/record whose 'state' field was tampered with, manually edited, or written by an incompatible passbolt version; replaying a state record that was already mutated.","commonSituations":"Users manipulating cookies during debugging; leftover state rows from a version upgrade with a changed state format; hitting the SSO callback with a forged state parameter.","solutions":["Restart the SSO login flow from the beginning to generate a fresh state.","Clear the corrupted SSO state record/cookie and retry.","Ensure the Sso plugin version is consistent across all app servers (no mixed deployments)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!SsoState::isValidState($stateRecord->state)) { /* regenerate state before callback */ }","typeGuard":null,"tryCatchPattern":"try { $svc->assertAndConsume($state, $settingsId, $uac); } catch (BadRequestException $e) { // restart SSO flow with a fresh state\n    return redirect('/sso/login'); }","preventionTips":["Never reuse or hand-edit state records/cookies.","Always initiate SSO login through the official endpoint to mint a state.","Keep all app servers on the same Sso plugin version."],"tags":["php","sso","state-validation","bad-request"],"backgroundTag":"invalid-state-transition","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"}