{"record":{"id":"f6ca4869acabe232","repo":"apache/pulsar","slug":"unable-to-obtain-an-access-token-e-getmessage","errorCode":null,"errorMessage":"Unable to obtain an access token: ${e.getMessage}","messagePattern":"Unable to obtain an access token: (.+?)","errorType":"exception","errorClass":"PulsarClientException.AuthenticationException","httpStatus":null,"severity":"error","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/TlsClientAuthFlow.java","lineNumber":142,"sourceCode":"        initialized = true;\n    }\n\n    public TokenResult authenticate() throws PulsarClientException {\n        // request an access token using TLS client authentication\n        ClientCredentialsExchangeRequest req = ClientCredentialsExchangeRequest.builder()\n                .clientId(this.clientId)\n                .audience(this.audience)\n                .scope(this.scope)\n                .authMethod(TokenEndpointAuthMethod.TLS_CLIENT_AUTH)\n                .build();\n        TokenResult tr;\n        if (!initialized) {\n            initialize();\n        }\n        try {\n            tr = this.exchanger.exchangeClientCredentials(req);\n        } catch (TokenExchangeException | IOException e) {\n            throw new PulsarClientException.AuthenticationException(\"Unable to obtain an access token: \"\n                    + e.getMessage());\n        }\n\n        return tr;\n    }\n\n    @Override\n    public void close() throws Exception {\n        super.close();\n        if (exchanger != null) {\n            exchanger.close();\n        }\n    }\n\n    @VisibleForTesting\n    String getClientId() {\n        return clientId;\n    }","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/TlsClientAuthFlow.java#L124-L160","documentation":"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.","triggerScenarios":"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.).","commonSituations":"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.","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."],"exampleFix":"// before\nString secret = System.getenv(\"CLIENT_SECRET\"); // stale rotated value -> 401 invalid_client\n// after\nString secret = loadFromSecretStore(\"pulsar-client-secret\"); // current credential","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    client = AuthenticationFactoryOAuth2.clientCredentials(issuerUrl, credFile, audience);\n} catch (org.apache.pulsar.client.api.PulsarClientException.AuthenticationException e) {\n    // message = 'Unable to obtain an access token: <reason>'\n    // TokenError codes (invalid_client, invalid_grant) -> fix credentials/audience\n    // IO reasons -> check network/proxy/TLS to token endpoint\n    throw new RuntimeException(\"OAuth2 token acquisition failed: \" + e.getMessage(), e);\n}","preventionTips":["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."],"tags":["oauth2","authentication","token-endpoint","pulsar-client"],"backgroundTag":"oauth-token-request-failed","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}