SonarQube Server: self-hosted (accessed via service connection)
SonarQube Extension for Azure DevOps: 8.2.3 (SonarQubePrepare@8, SonarQubeAnalyze@8, SonarQubePublish@8)
Scanner: dotnet scanner (scannerMode: dotnet)
What I am trying to achieve
Dynamically inject a SonarQube token fetched at pipeline runtime via sonar.token in SonarQubePrepare@8’s extraProperties, rather than relying on the static token stored in the service connection:
SonarQubeAnalyze@8 succeeds — the scanner honours sonar.token from extraProperties.
SonarQubePublish@8 fails with HTTP 401:
[ERROR] SonarQube Server: API GET '/api/metrics/search' failed. Axios Error message: Request failed with status code 401.
[ERROR] SonarQube Server: Error while executing task Publish: Could not fetch metrics
Could not fetch metrics
Root cause identified
SonarQubePrepare@8 stores the service connection credentials in a task variable SONAR_ENDPOINT
(JSON with data.url and data.username). SonarQubePublish@8 reads this variable directly
for its own API calls and never checks sonar.token from extraProperties. So even when sonar.token overrides authentication for the scanner successfully, Publish continues using
the original service connection token.
Expected behaviour
sonar.token set in extraProperties should be honoured by all three tasks uniformly,
including SonarQubePublish@8, so that dynamic token injection works end-to-end without
requiring internal variable manipulation.
Hey @Rumy, welcome to the Community! The intended usage of the SonarQube tasks is in conjunction with the service connection, and I suspect it was never implemented to be consistent with sonar.token in the way you expect. However, I do appreciate your thorough explanation of the issue and it’s interesting for us to know that you ran into this limitation. Could you elaborate a bit more on why do you want to do this?
Thank you for the response. The motivation comes from a token rotation setup.
We manage SonarQube tokens as part of a broader secret lifecycle management strategy where tokens are rotated automatically on a schedule. At scan time, the pipeline fetches the current valid token dynamically at runtime and injects it via sonar.token.
The problem with relying solely on the service connection is that it holds a static copy of the token. Every time a token rotates, the service connection would need to be updated separately — creating operational overhead and a window where it holds a stale token.
By fetching the token dynamically at runtime we get:
Always-fresh credentials without touching the service connection on every rotation
Centralized secret management with a full audit trail
Per-project token isolation — each project has its own token, so there is no single shared scanner token that is a natural fit for one service connection
The service connection in our setup exists only because SonarQubePrepare@8 requires one — ideally we would configure it with the server URL only, with authentication handled entirely via sonar.token.