passbolt/passbolt_api · error · BadRequestException

$exception->getMessage() from SsoSettingsGetService draft…

Error message

$exception->getMessage() from SsoSettingsGetService draft failure (dynamic), remapped to 400

What it means

In stage2AsAdmin, fetching the draft SSO settings via SsoSettingsGetService::getDraftByIdOrFail() can fail (draft missing, deleted, or wrong status). The controller catches any Exception and remaps its dynamic message to a 400 BadRequestException, chaining the original exception.

Solutions

  1. Re-open the SSO settings admin screen and restart the provider setup to generate a fresh draft before completing stage2.
  2. Check the sso_settings record in the database for the id in the state — confirm it exists with status DRAFT.
  3. Verify no concurrent admin session deleted/modified the settings draft (check audit/logs).
  4. Ensure the SSO state cookie and the settings draft belong to the same setup attempt; clear cookies and retry.
Defensive patterns

Strategy: try-catch

Validate before calling

const settings = await api.get('/sso/settings/' + ssoState.sso_settings_id + '.json');
if (!settings || settings.status !== 'draft') { throw new Error('SSO settings draft missing; restart setup'); }

Type guard

function hasValidDraft(state) { return state != null && typeof state.sso_settings_id === 'string' && state.sso_settings_id.length > 0; }

Try / catch

try { await stage2AsAdmin(state, code); } catch (e) { if (e.status === 400) { showAlert('SSO draft settings unavailable: ' + e.message + '. Restart provider setup.'); } }

Prevention

When it happens

Trigger: Admin completes SSO provider callback (stage2) but the referenced sso_settings_id in the state no longer points to a valid settings draft, e.g. the draft was saved/deleted or expired between stage1 redirect and stage2 callback.

Common situations: Two admins editing the same SSO settings concurrently — one saves/deletes the draft while the other's callback is in flight; session left open so long the draft was discarded; clicking an old bookmarked callback link.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

        }

        $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) {
            throw new BadRequestException($exception->getMessage(), 400, $exception);
        }

        try {
            $service = $this->ssoServiceFactory($cookieService, $settingsDto);
            $uac = $service->assertStateCodeAndGetUac($ssoState, $code, $this->User->ip(), $this->User->userAgent());
        } catch (OAuth2Exception $e) { // Remap 500 error with 400 when admin is setting up SSO
            throw new BadRequestException($e->getMessage(), 400, $e);
        }

        // Create authentication token for next step, e.g. activate settings
        $ssoAuthToken = $service->createAuthTokenToActiveSettings($uac, $service->getSettings()->id);

        $this->response = $this->getResponse()->withCookie($service->clearStateCookie());
        $this->redirect(Router::url("/sso/login/dry-run/success?token={$ssoAuthToken->token}", true));
    }
}

View on GitHub (pinned to 31c1bbc10f)