apache/pulsar · error · PulsarClientException.AuthenticationException
Unable to obtain an access token: ${e.getMessage}
Error message
Unable to obtain an access token: ${e.getMessage} What it means
TlsClientAuthFlow.authenticate sends a token request to the OAuth2 token endpoint. If the HTTP exchange throws IOException or the IdP returns an RFC 6749 token error surfaced as TokenExchangeException, a PulsarClientException.AuthenticationException is thrown with 'Unable to obtain an access token: <reason>'. Authentication with the authorization server failed.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/TlsClientAuthFlow.java:142
initialized = true;
}
public TokenResult authenticate() throws PulsarClientException {
// request an access token using TLS client authentication
ClientCredentialsExchangeRequest req = ClientCredentialsExchangeRequest.builder()
.clientId(this.clientId)
.audience(this.audience)
.scope(this.scope)
.authMethod(TokenEndpointAuthMethod.TLS_CLIENT_AUTH)
.build();
TokenResult tr;
if (!initialized) {
initialize();
}
try {
tr = this.exchanger.exchangeClientCredentials(req);
} catch (TokenExchangeException | IOException e) {
throw new PulsarClientException.AuthenticationException("Unable to obtain an access token: "
+ e.getMessage());
}
return tr;
}
@Override
public void close() throws Exception {
super.close();
if (exchanger != null) {
exchanger.close();
}
}
@VisibleForTesting
String getClientId() {
return clientId;
}View on GitHub (pinned to 820761864e)
Solutions
- Inspect the embedded message: a TokenError code like invalid_client means fix clientId/clientSecret/audience; an IO message means check connectivity to the token endpoint.
- Verify network reachability of the issuer/token endpoint (curl it; check proxy settings).
- Confirm issuerUrl points to the correct tenant/realm — token endpoint may have changed.
- Re-issue rotated credentials and update the client config or credentials file.
Example fix
// before
String secret = System.getenv("CLIENT_SECRET"); // stale rotated value -> 401 invalid_client
// after
String secret = loadFromSecretStore("pulsar-client-secret"); // current credential Defensive patterns
Strategy: try-catch
Try / catch
try {
client = AuthenticationFactoryOAuth2.clientCredentials(issuerUrl, credFile, audience);
} catch (org.apache.pulsar.client.api.PulsarClientException.AuthenticationException e) {
// message = 'Unable to obtain an access token: <reason>'
// TokenError codes (invalid_client, invalid_grant) -> fix credentials/audience
// IO reasons -> check network/proxy/TLS to token endpoint
throw new RuntimeException("OAuth2 token acquisition failed: " + e.getMessage(), e);
} Prevention
- Re-check clientId/clientSecret after any credential rotation.
- Verify the issuer's well-known metadata is reachable before wiring up the client.
- Test token acquisition with curl against the token endpoint using the same credentials.
- Confirm proxies/firewalls allow outbound HTTPS to the IdP.
When it happens
Trigger: authenticate() runs during Pulsar client OAuth2 login and exchanger.exchangeClientCredentials(req) either fails at the network/TLS layer (IOException) or the token endpoint responds 400/401 with a TokenError (invalid_client, invalid_grant, etc.).
Common situations: Wrong or rotated clientId/clientSecret; revoked credentials; misconfigured audience; IdP downtime; corporate proxy/firewall blocking the token endpoint; TLS trust issues between client and IdP.
Related errors
- Unsupported auth method: ${authMethod}
- Unsupported authentication type: ${type}
- No authentication parameters were provided
- Failed to perform HTTP request. res: ${res.statusCode}
- Unsupported token endpoint auth method: ${value}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/f6ca4869acabe232.
Report an issue: GitHub.