passbolt/passbolt_api · error · BadRequestException

The SSO state is invalid. User id mismatch.

Error message

The SSO state is invalid. User id mismatch.

What it means

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.

Solutions

  1. Retry the SSO login while logged in as the intended user only.
  2. Clear SSO state cookies/storage and start a fresh flow.
  3. Ensure your client doesn't reuse a state value across sessions or users.
Defensive patterns

Strategy: validation

Validate before calling

if ($stateRecord->user_id !== $currentUserId) { /* discard state and restart login */ }

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: Shared computers where two users start SSO login in the same browser; session switch mid-flow; automated tests reusing state fixtures across users.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/55222ce96e18269f. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Service/SsoStates/SsoStatesAssertService.php:97

     * @param \Passbolt\Sso\Model\Entity\SsoState $ssoState SSO state entity.
     * @param string $ssoSettingsId SSO Settings ID.
     * @param \App\Utility\ExtendedUserAccessControl $uac UAC object.
     * @return void
     */
    private function assert(SsoState $ssoState, string $ssoSettingsId, ExtendedUserAccessControl $uac): void
    {
        $errorMsg = __('The SSO state is invalid.') . ' ';

        if (!SsoState::isValidState($ssoState->state)) {
            throw new BadRequestException(trim($errorMsg));
        }

        if ($ssoState->isExpired()) {
            throw new BadRequestException($errorMsg . __('The SSO state is expired.'));
        }

        if ($ssoState->user_id !== $uac->getId() || !Validation::uuid($ssoState->user_id)) {
            throw new BadRequestException($errorMsg . __('User id mismatch.'));
        }

        if (Configure::read('passbolt.security.userIp')) {
            if ($ssoState->ip !== $uac->getUserIp()) {
                throw new BadRequestException($errorMsg . __('User IP mismatch.'));
            }
        }

        if (Configure::read('passbolt.security.userAgent')) {
            if ($ssoState->user_agent !== $uac->getUserAgent()) {
                throw new BadRequestException($errorMsg . __('User agent mismatch.'));
            }
        }

        if ($ssoState->sso_settings_id !== $ssoSettingsId || !Validation::uuid($ssoState->sso_settings_id)) {
            throw new BadRequestException($errorMsg . __('Settings mismatch.'));
        }
    }

View on GitHub (pinned to 31c1bbc10f)