pentaho/pentaho-kettle · error · HttpException
Unable to get authorization token
Error message
Unable to get authorization token
What it means
Thrown while MailInputMeta exchanges an authorization code (or credentials) for an OAuth2 access token via HTTP POST. Any non-200 status from the token endpoint raises HttpException, which is rethrown as a RuntimeException, aborting authentication for the Mail Input step.
Solutions
- Check the wrapped cause and the status line (response.getStatusLine()) for the provider's error (e.g. 400 invalid_grant)
- Verify client ID, client secret, tenant, and redirect_uri exactly match the OAuth app registration
- Ensure the environment variables substituted via variables.environmentSubstitute() resolve to correct values
- Confirm network/proxy access to login.microsoftonline.com or the configured token endpoint
- Regenerate the authorization code — codes are single-use and expire in minutes
Example fix
// before
if ( response.getStatusLine().getStatusCode() != HttpStatus.SC_OK ) {
throw new HttpException( "Unable to get authorization token " + response.getStatusLine().toString() );
}
// after
if ( response.getStatusLine().getStatusCode() != HttpStatus.SC_OK ) {
String body = EntityUtils.toString( response.getEntity() );
throw new HttpException( "Token endpoint returned " + response.getStatusLine()
+ ": " + body );
} Defensive patterns
Strategy: validation
Validate before calling
boolean tokenConfigValid = clientId != null && !clientId.isEmpty()
&& clientSecret != null && !clientSecret.isEmpty()
&& redirectUri != null && redirectUri.startsWith( "https://" );
if ( !tokenConfigValid ) {
throw new IllegalArgumentException( "OAuth client id/secret/redirect_uri must be set before token exchange" );
} Try / catch
try {
EmailAuthenticationResponse resp = meta.getAuthenticationResponse(...);
} catch ( RuntimeException e ) {
// inspect cause: HttpException status line or IOException
logError( "Token exchange failed: " + e.getCause().getMessage() );
} Prevention
- Verify redirect_uri exactly matches the OAuth app registration
- Regenerate authorization codes right before use (they expire quickly)
- Check proxy/firewall access to the token endpoint
- Validate env-variable substitutions resolve to non-empty values
When it happens
Trigger: POSTing the token request (redirect_uri, client id/secret form entity) to the OAuth provider and receiving a status other than 200 — bad client secret, expired/mismatched redirect URI, or unreachable/blocked endpoint. Also on IOException/HttpException during response read.
Common situations: Misconfigured OAuth app (wrong redirect URI or client secret), tenant/admin consent missing in Microsoft 365, network proxy blocking the token endpoint, or using a deactivated client.
Related errors
- Auth error
- CmsTokenProvider: Keycloak response did not contain…
- CmsTokenProvider: Keycloak token request failed — HTTP
- HTTP.Exception.Authentication
- HTTPPOST.Exception.Authentication
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/79d614fbe49972dc.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/email-messages/impl/src/main/java/org/pentaho/di/trans/steps/mailinput/MailInputMeta.java:1048
try (CloseableHttpClient client = HttpClientManager.getInstance().createDefaultClient()) {
HttpPost httpPost = new HttpPost( variables.environmentSubstitute( tokenUrl ) );
List<NameValuePair> form = new ArrayList<>();
form.add(new BasicNameValuePair("scope", variables.environmentSubstitute( scope ) ) );
form.add(new BasicNameValuePair("client_id", variables.environmentSubstitute( clientId ) ));
form.add(new BasicNameValuePair("client_secret", variables.environmentSubstitute( secretKey ) ) );
form.add(new BasicNameValuePair("grant_type", grantType));
if (grantType.equals(GRANTTYPE_REFRESH_TOKEN)) {
form.add(new BasicNameValuePair(GRANTTYPE_REFRESH_TOKEN, variables.environmentSubstitute( refreshToken ) ) );
}
if (grantType.equals(GRANTTYPE_AUTHORIZATION_CODE)) {
form.add(new BasicNameValuePair("code", variables.environmentSubstitute( authorizationCode ) ) );
form.add(new BasicNameValuePair("redirect_uri", variables.environmentSubstitute( redirectUri ) ) );
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(form, Consts.UTF_8);
httpPost.setEntity(entity);
try (CloseableHttpResponse response = client.execute(httpPost)) {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new HttpException("Unable to get authorization token " + response.getStatusLine().toString());
}
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(EntityUtils.toString(response.getEntity()), EmailAuthenticationResponse.class);
} catch ( HttpException | IOException e) {
throw new RuntimeException(e);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
View on GitHub (pinned to f3058517a1)