Changed username via API forces user account into externally managed

Must-share information (formatted with Markdown):

  • Version: sonarqube-2025.1.2.108896
  • Sonarqube Server / Community Build
  • deployed via zip
  • attempted to change the username for an employee
  • used API: /api/v2/users-management/users/{id}

used the API endpoint to change the username from Bob to Mary (example). Sample JSON payload:

{
 "login": "mmai",
 "name": "Mary Mai",
 "email": "mmai@domain.com", 
 "active": true,
 "local": true
}

While the API does return, it resets the local to false:

{
"id": "AXzcuII_hHToUQOqGHLb",
"login": "mmai",
"name": "Mary Mai",
"email": "mmai@domain.com",
"active": true,
"local": false,
"managed": false,
"externalLogin": "mmai",
"externalProvider": "sonarqube",
"externalId": "mmai",
"avatar": "e9a5f50b0db23a2ec0b18d3193f474d7",
"sonarQubeLastConnectionDate": "2026-06-03T20:35:57+0000",
"sonarLintLastConnectionDate": "2026-06-03T20:35:57+0000",
"scmAccounts": []
}

access log entry:
192.168.7.15 - - \[19/Jun/2026:21:15:25 +0000\] "PATCH /api/v2/users-management/users/AXzcuII_hHToUQOqGHLb HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36" "f04d7afb-edfc-4bfb-8c28-b49f4bb86e4b"

Notice the local value changes from true to false. Now the user cannot sign in and I can no longer manage the user from the web UI. subsequent attempts to reset the password via the api fails as well:

{"result":"Password cannot be changed when external authentication is used"}

I suspect that the first time I attempted to change the user’s login name, I didn’t specify that the local was set to true and it’s been set to false. Now I cannot set it to true.

How can I restore this user to locally/internally managed?

Hi @Joey_0, welcome to the Community!

PATCH/api/v2/users-management/users/{id} isn’t supposed to update the local field. If you check <your_sonarqube_url>/web_api_v2#/users-management/users/{id}--patch (API docs) you’ll see that the payload doesn’t have a login field, and in theory shouldn’t honor it.

The user state that you have share is quite bizarre indeed: "externalProvider": "sonarqube" tells us that it’s a local user, however, this contradicts "local": false, typically associated with SAML (or other authentication method). Could you clarify if this was originally a local user or a SAML/external user? Is your instance “managed” (SCIM enabled)? You can check this at Administration > General settings > Authentication.

All users have been local from the beginning, we haven’t had it linked up to any external user management system. At the referenced configuration page, SAML is not configured.

For comparison sake, all of the existing/other users have a similar external designation. Here’s an example of an existing user, no api changes made:

{
            "id": "AY98pJ6kRx1ZErAbQs_h",
            "login": "ejeff",
            "name": "E Jeff",
            "email": "ejeff@domain.com",
            "active": true,
            "local": true,
            "managed": false,
            "externalLogin": "ejeff",
            "externalProvider": "sonarqube",
            "externalId": "ejeff",
            "avatar": "33089bb682bb6210eb9ef785e817e708",
            "sonarQubeLastConnectionDate": "2026-02-06T17:22:18+0000",
            "sonarLintLastConnectionDate": null,
            "scmAccounts": []
        }

I think it would be interesting to look at your audit logs. They record changes to user accounts, so hopefully they might shine some light on the topic. I understand you wouldn’t share them here, so I would ask you if you could have a good look at them and try to reconstruct the trail of changer for that user. Try filtering events that have category = USER and newValue.userUuid = AXzcuII_hHToUQOqGHLb.

From the documentattion, Audit logs are only available in Enterprise versions.

I compared a pair of users, one never touched and this affected user from the DB perspective. The primary difference that sticks out is the user_local field is false for the affected user.

I know I generally shouldn’t update the database directly - and I haven’t yet - but could it be as simple as updating the column to true?

begin;
update users set user_local = true where uuid = 'AXzcuII_hHToUQOqGHLb';
commit;

No audit logs, I see… indeed it’s only available on Enterprise, and until now I didn’t have information on which edition you were running.

We generally advocate for not touching the DB directly unless it is a case of DB corruption, which seems to be the case here: this user’s state is pretty much corrupted (i.e. internally inconsistent). Updating the DB it’s not your only option though, you could just create a new user. In principle your SQL looks good to me, but run it at your own risk.

I’m going to flag this for the devs to have a look because it is possible that there is a bug that enabled this corrupted state to happen. It’s true that you’re on a relatively old version (2025.1), but still, worth checking just in case.

Before I attempt a database change, I just want to confirm that (currently) there isn’t any more of an alternative?

You mentioned the version we’re running is old, I’m open to upgrading to the latest 2025.1 release (or latest LTA version in general) but I could find no reference to an API issue that we’re discussing here.

Is there a Jira ticket I could follow on this topic if you’re raising it up to the development team?

Just giving an update here…

I’ve updated the user record, reverting the user_local value back to ‘true’. Initial testing looks good.

UPDATE public.users 
  SET user_local = true 
  WHERE uuid = 'AXzcuII_hHToUQOqGHLb';

Complete steps:

  1. stopped sonarqube / restricted user access
  2. database dump / backup (safety first or a close second :wink: )
  3. ran update sql
  4. started sonarqube, attempted to manage user - no errors/warnings that the user isn’t locally managed
  5. opened sonarqube to staff
  6. user tested login / password reset

Hope this helps someone in the future.

Joey

Hey @Joey_0, glad you solved it and thanks for circling back and writing down the recipe you followed, your engagement is appreciated! I’m still puzzled as to how this happened, but anyway, it’s flagged for the devs so that they are aware that this happened in the wild, perhaps there are some missing safeguards somewhere in the code…