passbolt/passbolt_api · error · BadRequestException
The user is missing for the SSO state.
Error message
The user is missing for the SSO state.
What it means
assertStateCodeAndGetUac() converts an OAuth state into a UAC, but the state must carry a user_id. When the SSO state entity has a null user_id (state created without a bound user), a BadRequestException is thrown because the flow cannot identify which user is logging in.
Solutions
- Ensure the flow creates the SSO state with a user_id (associate the state with the user before redirecting to the IdP)
- If the flow intentionally has no bound user (e.g. first-time SSO setup), use the endpoint designed for user-less states instead of assertStateCodeAndGetUac
- Start the SSO login flow again to generate a fresh state with the user bound
Example fix
// before $state = $this->SsoStates->create($settingsId, null); // no user // after $state = $this->SsoStates->create($settingsId, $uac->getId()); // bind user id
Defensive patterns
Strategy: validation
Validate before calling
if ($ssoState->user_id === null) {
// do not call assertStateCodeAndGetUac; use user-less flow endpoint or re-create state
} Type guard
function stateHasUser(object $state): bool { return $state->user_id !== null; } Try / catch
try {
$uac = $service->assertStateCodeAndGetUac($ssoState, $code, $ip, $ua);
} catch (BadRequestException $e) {
if ($e->getMessage() === 'The user is missing for the SSO state.') {
// restart flow with a user-bound state
}
} Prevention
- Always create SSO states with a bound user id
- Use the dedicated setup/recover endpoints for user-less flows
- Expire and regenerate stale states
When it happens
Trigger: Recovering/completing an SSO login whose state was generated without a user (e.g. anonymous SSO-recover setup flows, or states created before user association), then hitting the assert/login endpoint with that state code.
Common situations: SSO recover/setup flows where the user id is only attached later in the flow; replaying an old state; race where state was created by a different endpoint variant; bugs in plugin code creating states without user binding.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- The settings status is invalid.
- Ajax/Json request not supported.
- Ajax/Json request not supported.
- Ajax/Json request not supported.
- Ajax/Json request not supported.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/261c838115614e62.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Service/Sso/AbstractSsoService.php:190
* Check a given state against authentication token and extended user info
*
* @param \Passbolt\Sso\Model\Entity\SsoState $ssoState SSO state entity
* @param string $code client ip
* @param string $ip user agent
* @param string $userAgent user agent
* @throws \Cake\Http\Exception\BadRequestException If the user_id in SSO state is `null`.
* @throws \Cake\Http\Exception\BadRequestException if the user does not exist or is inactive
* @throws \Cake\Http\Exception\BadRequestException if resource owner username is not provider or does not match user entity
* @return \App\Utility\ExtendedUserAccessControl
*/
public function assertStateCodeAndGetUac(
SsoState $ssoState,
string $code,
string $ip,
string $userAgent
): ExtendedUserAccessControl {
if ($ssoState->user_id === null) {
throw new BadRequestException(__('The user is missing for the SSO state.'));
}
try {
$user = (new UserGetService())->getActiveNotDeletedNotDisabledOrFail($ssoState->user_id);
} catch (NotFoundException $exception) {
throw new BadRequestException(__('The user does not exist or is not active.'), 400, $exception);
}
// Check the token against extended user info and consume it
$uac = new ExtendedUserAccessControl($user->role->name, $user->id, $user->username, $ip, $userAgent);
(new SsoStatesAssertService())->assertAndConsume($ssoState, $this->getSettings()->id, $uac);
try {
// Assert access request and if it matches current suer
$resourceOwner = $this->getResourceOwnerAndAssertAgainstUser($code, $user);
$this->assertResourceOwnerAgainstSsoState($resourceOwner, $ssoState);
} catch (Exception $e) {View on GitHub (pinned to 31c1bbc10f)