passbolt/passbolt_api · error · BadRequestException
The SSO state is invalid.
Error message
The SSO state is invalid.
What it means
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.
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).
Defensive patterns
Strategy: try-catch
Validate before calling
if (!SsoState::isValidState($stateRecord->state)) { /* regenerate state before callback */ } Try / catch
try { $svc->assertAndConsume($state, $settingsId, $uac); } catch (BadRequestException $e) { // restart SSO flow with a fresh state
return redirect('/sso/login'); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Service provider invalid.
- Service provider missing.
- Service provider not supported.
- The SSO state is invalid. The SSO state is expired.
- Ajax/Json request not supported.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/8ee678b9fb40836f.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Service/SsoStates/SsoStatesAssertService.php:89
$this->consume($ssoState);
}
/**
* Makes assertions against the SSO state entity, current user, and settings ID.
* This is used to ensure data integrity between request user/client, settings.
*
* @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()) {View on GitHub (pinned to 31c1bbc10f)