Java Auth x EWS
Docs and code samples for Java Auth
Last updated
Docs and code samples for Java Auth
Last updated
This old example is using the "basic auth" method
// Using Microsoft.Identity.Client 4.22.0
// Configure the MSAL client to get tokens
var pcaOptions = new PublicClientApplicationOptions
{
ClientId = ConfigurationManager.AppSettings["appId"],
TenantId = ConfigurationManager.AppSettings["tenantId"]
};
var pca = PublicClientApplicationBuilder
.CreateWithApplicationOptions(pcaOptions).Build();
// The permission scope required for EWS access
var ewsScopes = new string[] { "https://outlook.office365.com/EWS.AccessAsUser.All" };
// Make the interactive token request
var authResult = await pca.AcquireTokenInteractive(ewsScopes).ExecuteAsync();
...then pass the token to the ewsclient
// Configure the ExchangeService with the access token
var ewsClient = new ExchangeService();
ewsClient.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
ewsClient.Credentials = new OAuthCredentials(authResult.AccessToken);
private static IAuthenticationResult acquireTokenUsernamePassword() throws Exception {
// Load token cache from file and initialize token cache aspect. The token cache will have
// dummy data, so the acquireTokenSilently call will fail.
TokenCacheAspect tokenCacheAspect = new TokenCacheAspect("sample_cache.json");
PublicClientApplication pca = PublicClientApplication.builder(CLIENT_ID)
.authority(AUTHORITY)
.setTokenCacheAccessAspect(tokenCacheAspect)
.build();
Set<IAccount> accountsInCache = pca.getAccounts().join();
// Take first account in the cache. In a production application, you would filter
// accountsInCache to get the right account for the user authenticating.
IAccount account = accountsInCache.iterator().next();
IAuthenticationResult result;
try {
SilentParameters silentParameters =
SilentParameters
.builder(SCOPE, account)
.build();
// try to acquire token silently. This call will fail since the token cache
// does not have any data for the user you are trying to acquire a token for
result = pca.acquireTokenSilently(silentParameters).join();
} catch (Exception ex) {
if (ex.getCause() instanceof MsalException) {
UserNamePasswordParameters parameters =
UserNamePasswordParameters
.builder(SCOPE, USER_NAME, USER_PASSWORD.toCharArray())
.build();
// Try to acquire a token via username/password. If successful, you should see
// the token and account information printed out to console
result = pca.acquireToken(parameters).join();
} else {
// Handle other exceptions accordingly
throw ex;
}
}
return result;
}
Sample codes from Microsoft below
private static IAuthenticationResult acquireTokenUsernamePassword(PublicClientApplication pca,
Set<String> scope,
IAccount account,
String username,
String password) throws Exception {
IAuthenticationResult result;
try {
SilentParameters silentParameters =
SilentParameters
.builder(scope)
.account(account)
.build();
// Try to acquire token silently. This will fail on the first acquireTokenUsernamePassword() call
// because the token cache does not have any data for the user you are trying to acquire a token for
result = pca.acquireTokenSilently(silentParameters).join();
System.out.println("==acquireTokenSilently call succeeded");
} catch (Exception ex) {
if (ex.getCause() instanceof MsalException) {
System.out.println("==acquireTokenSilently call failed: " + ex.getCause());
UserNamePasswordParameters parameters =
UserNamePasswordParameters
.builder(scope, username, password.toCharArray())
.build();
// Try to acquire a token via username/password. If successful, you should see
// the token and account information printed out to console
result = pca.acquireToken(parameters).join();
System.out.println("==username/password flow succeeded");
} else {
// Handle other exceptions accordingly
throw ex;
}
}
return result;
}
public static String getAccessToken() throws Exception {
Set<String> scope = new HashSet<String>();
scope.add("https://outlook.office365.com/.default");
String username = "test1@onmicrosoft.com";
String password = "userPass";
String clientId = "xxxxxb-f4be-4e2e-95dd-7aa4f5dxxxxx";
String tenantId = "xxxxx65f-f7e3-4bc3-841f-13b29xxxxx";
String authority =
"https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/token";
PublicClientApplication pca = PublicClientApplication.builder(clientId)
.authority(authority)
.build();
//Get list of accounts from the application's token cache, and search them for the configured username
//getAccounts() will be empty on this first call, as accounts are added to the cache when acquiring a token
Set<IAccount> accountsInCache = pca.getAccounts().join();
IAccount account = getAccountByUsername(accountsInCache, username);
//Attempt to acquire token when user's account is not in the application's token cache
IAuthenticationResult result = acquireTokenUsernamePassword(pca, scope, account, username, password);
System.out.println("Account username: " + result.account().username());
System.out.println("Access token: " + result.accessToken());
System.out.println("Id token: " + result.idToken());
System.out.println();
accountsInCache = pca.getAccounts().join();
account = getAccountByUsername(accountsInCache, username);
//Attempt to acquire token again, now that the user's account and a token are in the application's token cache
result = acquireTokenUsernamePassword(pca, scope, account, username, password);
System.out.println("Account username: " + result.account().username());
System.out.println("Access token: " + result.accessToken());
System.out.println("Id token: " + result.idToken());
return "";
}
private static IAccount getAccountByUsername(final Set<IAccount> accountsInCache, final String username) {
if (accountsInCache.isEmpty()) {
System.out.println("==No accounts in cache");
} else {
System.out.println("==Accounts in cache: " + accountsInCache.size());
for (IAccount account : accountsInCache) {
if (account.username().equals(username)) {
return account;
}
}
}
return null;
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* Azure resource owner password credential (ROPC) token provider
* https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
* https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
* https://portal.azure.com
* https://developer.microsoft.com/en-us/graph/graph-explorer/#
* token parser https://jwt.io
* </p>
*/
class AzureROPCTokenProvider implements ITokenProvider {
private static final String GRANT_TYPE = "password";
private final String clientId;
private final String clientSecret;
private final String userName;
private final String password;
private final String tenant;
private final String scope;
private OAuthToken token;
public AzureROPCTokenProvider(String tenant, String clientId, String clientSecret,
String userName, String password, String[] scopeAr) {
this.tenant = tenant;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.userName = userName;
this.password = password;
this.scope = joinToStr(scopeAr, " ");
}
public synchronized OAuthToken getAccessToken(boolean ignoreExistingToken) {
if (this.token != null && !this.token.getExpired() && !ignoreExistingToken)
return this.token;
token = null;
Map<String, String> tokenArgs = geToken();
java.util.Calendar c = java.util.Calendar.getInstance();
c.add(java.util.Calendar.SECOND, Integer.parseInt(tokenArgs.get("expires_in")));
token = new OAuthToken(tokenArgs.get("access_token"), TokenType.AccessToken, c.getTime());
return token;
}
public final OAuthToken getAccessToken() {
return getAccessToken(false);
}
public void dispose() {
}
private String getEncodedParameters() {
return "client_id=" + urlEncode(clientId) + "&scope=" + urlEncode(scope) + "&username=" + urlEncode(userName)
+ "&password=" + urlEncode(password) + "&grant_type="
+ urlEncode(GRANT_TYPE);
}
private String getUri() {
if (tenant == null || tenant.trim().isEmpty())
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
else
return "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token";
}
private Map<String, String> geToken() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(getUri()).openConnection();
connection.setRequestMethod("POST");
byte[] requestData = getEncodedParameters().getBytes(StandardCharsets.UTF_8);
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", "" + requestData.length);
final OutputStream st = connection.getOutputStream();
try {
st.write(requestData, 0, requestData.length);
} finally {
st.flush();
st.close();
}
connection.connect();
if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST) {
throw new IllegalAccessError("Operation failed: " + connection.getResponseCode() + "/" +
connection.getResponseMessage() + "\r\nDetails:\r\n{2}"
+ readInputStream(connection.getErrorStream()));
}
String responseText = readInputStream(connection.getInputStream());
Map<String, String> result = new HashMap<>();
String[] fromJsonToKeyValue = responseText.replace("{", "").replace("}", "")
.replace("\"", "").replace("\r", "")
.replace("\n", "").split(",");
for (String keyValue : fromJsonToKeyValue) {
String[] pair = keyValue.split(":");
String name = pair[0].trim().toLowerCase();
String value = urlDecode(pair[1].trim());
result.put(name, value);
}
return result;
} catch (IOException e) {
throw new IllegalAccessError(e.getMessage());
}
}
static String urlEncode(String value) {
try {
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
throw new IllegalAccessError(e.getMessage());
}
}
static String urlDecode(String value) {
try {
return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
throw new IllegalAccessError(e.getMessage());
}
}
static String readInputStream(InputStream is) {
if (is == null)
return "";
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder result = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
result.append(line);
}
} catch (IOException e) {
// ignore
}
return result.toString();
}
static String joinToStr(String[] arr, String sep) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
if (i > 0)
sb.append(sep);
sb.append(arr[i]);
}
return sb.toString();
}
}
...which needs to be replaced with the code snippets by getting a token first
The example above is using the "Interactive" method for auth; if we need to use the "Non-Interactive" method, we need to use another method to get the token, like .
More examples can be found