passbolt/passbolt_api · warning · BadRequestException

The SSO state type is invalid.

Error message

The SSO state type is invalid.

What it means

Thrown in the default arm of the switch in stage2 of the SSO controller when the SSO state's type is not one of the recognized values (e.g. the expected mfa/recover/register/login state types). The state cookie is exchanged for an SsoState entity, and its 'type' field must match a branch the controller knows how to handle. This is a server-side guard against corrupted or forged state cookies.

Solutions

  1. Clear the passbolt SSO state cookie in the browser and restart the SSO flow from the beginning (login/recover/register).
  2. Inspect the SsoState entity produced from the cookie (plugins/PassboltEe/Sso) and confirm the 'type' value matches one of the SsoState::TYPE_* constants handled in stage2.
  3. Verify the browser is using the correct server version — mismatched plugin versions can produce unknown state types; run 'ddev refresh' to sync migrations and cache.
  4. Check for a proxy/CDN serving an old cached callback page with an outdated state.
Defensive patterns

Strategy: validation

Validate before calling

const stateTypes = ['mfa','recover','register','login'];
if (!stateTypes.includes(ssoState.type)) { throw new Error('Unsupported SSO state type: ' + ssoState.type); }

Type guard

function isKnownSsoStateType(t) { return typeof t === 'string' && ['mfa','recover','register','login'].includes(t); }

Try / catch

try { await completeStage2(state); } catch (e) { if (e.status === 400 && /state type is invalid/.test(e.message)) { clearSsoCookies(); restartSsoFlow(); } else { throw e; } }

Prevention

When it happens

Trigger: A user hits the SSO stage2 callback URL with a state cookie whose decrypted SsoState entity carries a 'type' value outside the set the switch statement handles (e.g. an old or invalid serialized state).

Common situations: Stale SSO cookies left over from a previous passbolt version whose state type no longer exists; a truncated/corrupted cookie; a user replaying an old callback URL with a cookie from a different flow; plugin upgrades between CE/EE SSO v1 and v2 that changed state types.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Controller/AbstractSso2Stage2Controller.php:199

                        $code,
                        $this->User->ip(),
                        $this->User->userAgent(),
                        $this->getProviderName()
                    );
                } catch (Exception $e) {
                    $event = new Event(self::EVENT_PROVIDER_ERROR_RESOURCE_OWNER, $this, ['exception' => $e]);
                    $this->getEventManager()->dispatch($event);
                    // To map 500(internal error/provider specific exceptions) to 4xx exception
                    if (isset($event->getResult()['customException'])) {
                        $e = $event->getResult()['customException'];
                    }

                    throw $e;
                }

                break;
            default:
                throw new BadRequestException(__('The SSO state type is invalid.'));
        }

        $this->response = $this->getResponse()->withCookie($service->clearStateCookie());
        $this->redirect($successUrl);
    }

    /**
     * @param \App\Service\Cookie\AbstractSecureCookieService $cookieService Cookie service
     * @param \Passbolt\Sso\Model\Entity\SsoState $ssoState SSO state.
     * @param string $code jwt
     * @return void
     */
    protected function stage2AsAdmin(AbstractSecureCookieService $cookieService, SsoState $ssoState, string $code): void
    {
        try {
            // Get the draft settings
            $settingsDto = (new SsoSettingsGetService())->getDraftByIdOrFail($ssoState->sso_settings_id, true);
        } catch (Exception $exception) {

View on GitHub (pinned to 31c1bbc10f)