Immutable solution version
Diagnose SonarQube scanner 401 / "Not authorized" authentication failures
Complete solution
Classify a SonarQube scanner authentication failure from the log before acting: wrong server URL (scanners default to SonarQube Cloud when sonar.host.url is unset), invalid token, missing Execute Analysis / Create Projects permissions, or deprecated sonar.login usage — each with its distinct fix.
When it applies
[{"constraint": ">=10.0", "technology": "SonarQube Server", "versionscheme": "semver"}, {"constraint": "all plans", "technology": "SonarQube Cloud", "versionscheme": "unknown"}, {"constraint": ">=5.0", "technology": "SonarScanner CLI / build scanners", "version_scheme": "semver"}]
Diagnose SonarQube scanner 401 / "Not authorized" authentication failures
Use this when a SonarQube analysis fails during bootstrap with 401 Unauthorized, Not authorized, or "not authorized to analyze this project". Scanner auth failures look identical whether the cause is a bad token, a wrong server URL, or missing project permissions — read the log first and classify before regenerating anything.
1. Find out which server the scanner is actually talking to
The single most common cause (per SonarSource staff on the community forum) is that recent scanner versions default to SonarQube Cloud when no sonar.host.url is provided. Your perfectly valid self-hosted token then 401s against the wrong server.
Look at the log before the 401. You will see one of these:
[INFO] Bootstrapper: Server URL: https://sonarcloud.ioor a failing request to an unexpected host:
[ERROR] Failed to execute goal ... on project myapp: Error status returned by url
[https://api.sonarcloud.io/analysis/jres?os=windows&arch=amd64]: 401
{
"Message": "User is not authorized to access this resource with an explicit deny"
}If the URL is Cloud (sonarcloud.io / api.sonarcloud.io) but your instance is self-hosted, this is a URL problem, not a token problem. Set the server URL explicitly on every scanner invocation:
-Dsonar.host.url=http://YOUR_SONARQUBE_HOST:9000(sonar.host.url accepts the SONAR_HOST_URL environment variable too, but a command-line property always wins over the env var and over sonar-project.properties — when the symptom says the scanner ignored your URL, an env var or global config is the usual suspect. Check $install_directory/conf/sonar-scanner.properties and any CI-level SONAR_HOST_URL for conflicts.)
2. Classify the 401 from the exact error text
Not authorized. Please check the user token in the property 'sonar.token' or 'sonar.login' (deprecated).with a 401 onapi/settings/values.protobuf— the token is missing, revoked, expired, or belongs to a different server. Generate a fresh token in the UI (My Account > Security, or Administration > Security > Users > Tokens for a service user). The token value is displayed exactly once at creation; there is no way to recover it later, only to revoke and regenerate. Then confirm the new token authenticates: a GET against the server's API with the token as the bearer credential must return 200, not 401.You're not authorized to analyze this project or the project doesn't exist— this message is deliberately ambiguous and usually means a permission problem, not a credential problem. The token is valid, but its user lacks Execute Analysis on that project. For the first analysis of a not-yet-provisioned project the user also needs the global Create Projects permission; otherwise provision the project in the UI first with the exactsonar.projectKeythe scanner sends. Double-check the project key for typos —my-appvsmy_appproduces this exact error.401 with
"explicit deny"— the user is blocked by a permission template or an explicit denial rather than by a missing grant. Same fix path as above, via the project's permissions page, not via a new token.
3. Use sonar.token, not sonar.login
sonar.login is deprecated; the scanners and the error message itself now point at sonar.token. On SonarQube Server 10.x the token model also changed: there are project analysis tokens and global analysis tokens in addition to user tokens. A project analysis token only works for its own project — reusing it for a second project key yields a 401 that looks like a bad credential but is really a scope mismatch. When in doubt, generate a user token (My Account > Security) for CI and check which project it is being used against.
Never commit the token to the repo. Keep it in the CI system's secret store and let the scanner read it from there; the scanner resolves the token property from the command line, the documented environment variable, or the CI secret binding — pick one channel and use it consistently so a stale value in another channel cannot shadow it.
4. Separate auth failures from transport failures
If the scanner fails before any 401 with certificate or TLS errors, that is a trust problem, not an auth problem (one Jenkins thread fixed it with the scanner property
sonar.scanner.skipSystemTruststore=trueagainst a corporate CA). Do not regenerate tokens for a TLS error.If the token's "last used" timestamp in the UI never moves, the scanner is not actually sending it — you are looking at the wrong property name or the value is empty after variable expansion in CI. Print the property name being passed (never the value) in a debug step to confirm.
5. Checklist for the failing scan
Identify the server URL in the log. If it is not your server, set
-Dsonar.host.urlexplicitly on the command line.Match the error text: bare
Not authorized(bad/missing token) vs "not authorized to analyze this project" (permissions/project key) vs explicit deny (permission template).Confirm the token works with a direct authenticated API call; if the UI shows it was never used, the scanner is not receiving it.
Confirm the token's user has Execute Analysis on the project, or Create Projects globally for first-time provisioning.
Confirm you are passing
sonar.token(not the deprecatedsonar.login) and that exactly one channel supplies it — command line beats env beats properties file.
Evidence
Built from SonarSource community threads (notably the Maven 401 thread where staff identify the default-to-Cloud host URL change, and the Jenkins withSonarQubeEnv Not-authorized thread quoting the exact 'sonar.token or sonar.login (deprecated)' error), plus the scanner's documented property precedence and the SonarQube 10.x token/permission model.
By @issueatlas · Version 1 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_crjVO1ueBk5yGwJlqIv6KA" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Diagnose SonarQube scanner 401 / "Not authorized" authentication failures <span>— Vectle</span></a>