SonarSource/sonarqube · error · IllegalStateException
Unable to get a token:
Error message
Unable to get a token:
What it means
OAuthMicrosoftRestClient.getAccessTokenFromClientCredentialsGrantFlow calls ScribeJava's client-credentials token request to Azure AD. If that call fails with IOException or ExecutionException (network failure, bad credentials, malformed response), it rethrows as IllegalStateException 'Unable to get a token: <cause>'.
Source
Thrown at server/sonar-server-common/src/main/java/org/sonar/server/oauth/OAuthMicrosoftRestClient.java:37
*/
package org.sonar.server.oauth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.oauth.OAuth20Service;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
public class OAuthMicrosoftRestClient {
public String getAccessTokenFromClientCredentialsGrantFlow(String host, String clientId, String clientSecret, String tenant, String scope) {
final OAuth20Service service = new ServiceBuilder(clientId)
.apiSecret(clientSecret)
.defaultScope(scope)
.build(new ScribeMicrosoftOauth2Api(host, tenant));
try {
return service.getAccessTokenClientCredentialsGrant().getAccessToken();
} catch (IOException | ExecutionException e) {
throw new IllegalStateException("Unable to get a token: " + e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted while getting a token: " + e);
}
}
}
View on GitHub (pinned to 184c821202)
Solutions
- Verify client id, client secret, tenant and scope values; rotate the secret if expired.
- Test connectivity to the token endpoint (curl https://login.microsoftonline.com) including proxy settings.
- Check the nested cause in logs for Azure's OAuth error (invalid_client, unauthorized_client) and fix the app registration.
- Confirm the ScribeMicrosoftOauth2Api host/tenant configuration matches your Azure tenant.
Example fix
// before
new OAuthMicrosoftRestClient(wrongTenantHost, clientId, oldSecret, scope);
// after
new OAuthMicrosoftRestClient(new Host("https://login.microsoftonline.com", "<tenant-id>"), clientId, rotatedSecret, scope); Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight checks before exchanging the token
Objects.requireNonNull(clientId); Objects.requireNonNull(clientSecret);
try (var s = new java.net.Socket(host.url().getHost(), 443)) { /* reachable */ } Try / catch
try { token = oauthClient.getAccessTokenFromClientCredentialsGrantFlow(); } catch (IllegalStateException e) { log.error("Microsoft token exchange failed: {}", e.getMessage(), e); throw new AuthenticationException(e.getMessage(), e); } Prevention
- Rotate and verify Azure client secrets before expiry
- Confirm tenant id and host match your Azure AD setup
- Check outbound proxy/firewall access to login.microsoftonline.com
- Log and inspect the nested cause for Azure OAuth error codes
When it happens
Trigger: Calling the Microsoft OAuth client-credentials flow when Azure AD returns an error (invalid client secret, wrong tenant/host), or network connectivity to login.microsoftonline.com fails.
Common situations: Expired or wrong client secret; tenant id or host misconfigured; Azure AD app not granting admin consent; proxy blocking outbound HTTPS; Azure outage.
Related errors
- Unable to contact Bitbucket Cloud servers: Configure the OAu
- Unable to contact Bitbucket Cloud servers: Check your creden
- Unable to contact Bitbucket Cloud servers
- Failed to validate configuration, check URL and Private Key
- Can not get Bitbucket user profile. HTTP code: %s, response:
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/364fed8882438b19.
Report an issue: GitHub.