{"record":{"id":"261c838115614e62","repo":"passbolt/passbolt_api","slug":"the-user-is-missing-for-the-sso-state","errorCode":null,"errorMessage":"The user is missing for the SSO state.","messagePattern":"The user is missing for the SSO state\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Service/Sso/AbstractSsoService.php","lineNumber":190,"sourceCode":"     * Check a given state against authentication token and extended user info\n     *\n     * @param \\Passbolt\\Sso\\Model\\Entity\\SsoState $ssoState SSO state entity\n     * @param string $code client ip\n     * @param string $ip user agent\n     * @param string $userAgent user agent\n     * @throws \\Cake\\Http\\Exception\\BadRequestException If the user_id in SSO state is `null`.\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the user does not exist or is inactive\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if resource owner username is not provider or does not match user entity\n     * @return \\App\\Utility\\ExtendedUserAccessControl\n     */\n    public function assertStateCodeAndGetUac(\n        SsoState $ssoState,\n        string $code,\n        string $ip,\n        string $userAgent\n    ): ExtendedUserAccessControl {\n        if ($ssoState->user_id === null) {\n            throw new BadRequestException(__('The user is missing for the SSO state.'));\n        }\n\n        try {\n            $user = (new UserGetService())->getActiveNotDeletedNotDisabledOrFail($ssoState->user_id);\n        } catch (NotFoundException $exception) {\n            throw new BadRequestException(__('The user does not exist or is not active.'), 400, $exception);\n        }\n\n        // Check the token against extended user info and consume it\n        $uac = new ExtendedUserAccessControl($user->role->name, $user->id, $user->username, $ip, $userAgent);\n        (new SsoStatesAssertService())->assertAndConsume($ssoState, $this->getSettings()->id, $uac);\n\n        try {\n            // Assert access request and if it matches current suer\n            $resourceOwner = $this->getResourceOwnerAndAssertAgainstUser($code, $user);\n\n            $this->assertResourceOwnerAgainstSsoState($resourceOwner, $ssoState);\n        } catch (Exception $e) {","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Service/Sso/AbstractSsoService.php#L172-L208","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n$state = $this->SsoStates->create($settingsId, null); // no user\n// after\n$state = $this->SsoStates->create($settingsId, $uac->getId()); // bind user id","handlingStrategy":"validation","validationCode":"if ($ssoState->user_id === null) {\n    // do not call assertStateCodeAndGetUac; use user-less flow endpoint or re-create state\n}","typeGuard":"function stateHasUser(object $state): bool { return $state->user_id !== null; }","tryCatchPattern":"try {\n    $uac = $service->assertStateCodeAndGetUac($ssoState, $code, $ip, $ua);\n} catch (BadRequestException $e) {\n    if ($e->getMessage() === 'The user is missing for the SSO state.') {\n        // restart flow with a user-bound state\n    }\n}","preventionTips":["Always create SSO states with a bound user id","Use the dedicated setup/recover endpoints for user-less flows","Expire and regenerate stale states"],"tags":["sso","state","bad-request","missing-user"],"backgroundTag":"missing-required-argument","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}