{"record":{"id":"55222ce96e18269f","repo":"passbolt/passbolt_api","slug":"the-sso-state-is-invalid-user-id-mismatch","errorCode":null,"errorMessage":"The SSO state is invalid. User id mismatch.","messagePattern":"The SSO state is invalid\\. User id mismatch\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Service/SsoStates/SsoStatesAssertService.php","lineNumber":97,"sourceCode":"     * @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()) {\n                throw new BadRequestException($errorMsg . __('User agent mismatch.'));\n            }\n        }\n\n        if ($ssoState->sso_settings_id !== $ssoSettingsId || !Validation::uuid($ssoState->sso_settings_id)) {\n            throw new BadRequestException($errorMsg . __('Settings mismatch.'));\n        }\n    }","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Service/SsoStates/SsoStatesAssertService.php#L79-L115","documentation":"Thrown by SsoStatesAssertService::assert when the user_id stored in the SSO state does not match the authenticated user performing the assertion (ExtendedUserAccessControl), or the stored user_id is not a valid UUID. This prevents a state generated for one user from being consumed by another.","triggerScenarios":"Completing the SSO callback while logged in as a different user than the one who initiated the SSO flow; multiple browser profiles/accounts sharing and mixing state cookies; a corrupted/tampered state record with a malformed user_id.","commonSituations":"Shared computers where two users start SSO login in the same browser; session switch mid-flow; automated tests reusing state fixtures across users.","solutions":["Retry the SSO login while logged in as the intended user only.","Clear SSO state cookies/storage and start a fresh flow.","Ensure your client doesn't reuse a state value across sessions or users."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if ($stateRecord->user_id !== $currentUserId) { /* discard state and restart login */ }","typeGuard":null,"tryCatchPattern":"try { $svc->assertAndConsume($state, $settingsId, $uac); } catch (BadRequestException $e) { if (str_contains($e->getMessage(), 'User id mismatch')) { /* restart flow as the same user */ } throw $e; }","preventionTips":["Don't switch user sessions between starting and completing SSO login.","Avoid shared browsers mixing accounts during SSO flows.","Generate one state per user session and never share it."],"tags":["php","sso","state-mismatch","security"],"backgroundTag":"invalid-identifier","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"}