I am still having trouble accessing the token server. I am not using the MSAL libraries, but rather am accessing it directly. I am going to then use that token to send the email via java mail.
Using the scope: "https://outlook.office.com/SMTP.SendAsApp" causes the server to respond with "400 - Bad Request" and using the scope: "https://outlook.office365.com/.default" (which was how it was previously documented) causes the server to respond with "401 - Unauthorized".
Here is my code that accesses the token server. Please let me know if you see any issues with what I am doing. Thanks in advance!
public class OAuthToken {
public String getAuthToken() throws IOException, NoSuchAlgorithmException, KeyManagementException {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// These are dummy values. I have removed the actual values that allow connections to my server.
String clientId = "my-client-id";
String tenantId = "my-tenant-id";
String scope = "https://outlook.office.com/SMTP.SendAsApp";
String client_secret = "my-client-secret";
String grant_type = "client_credentials";
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
StringBuilder data = new StringBuilder();
data.append("client_id=").append(clientId).append("&");
data.append("scope=").append(scope).append("&");
data.append("client_secret=").append(client_secret).append("&");
data.append("grant_type=").append(grant_type);
byte[] byteArray = data.toString().getBytes(StandardCharsets.UTF_8);
String urlString = "https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/token";
URL url = new URL(urlString);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Host", "login.microsoftonline.com");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("charset", "utf-8");
connection.setRequestProperty("Content-Length", Integer.toString(byteArray.length));
connection.setConnectTimeout(5000);
connection.setUseCaches(false);
connection.setDoOutput(true);
try (OutputStream postStream = connection.getOutputStream()) {
postStream.write(byteArray, 0, byteArray.length);
}
// Debug information...
int responseCode = connection.getResponseCode();
String responseMessage = connection.getResponseMessage();
System.out.println("Response code = " + responseCode + ", Response description = " + responseMessage);
InputStreamReader reader = new InputStreamReader(connection.getInputStream());
String accessToken;
try (BufferedReader in = new BufferedReader(reader)) {
String json = in.readLine();
if (json.length() > 0)
System.out.println("Json String = " + json);
else
throw new IOException("No response returned from server while attempting to acquire access token.");
// Parse the Json response and retrieve the Access Token
Gson gson = new Gson();
Type mapType = new TypeToken<Map<String,String>>(){}.getType();
Map<String,String> response = gson.fromJson(json, mapType);
accessToken = response.get("access_token");
System.out.println("Access Token = " + accessToken);
} finally {
connection.disconnect();
}
return accessToken;
}