Utilizing the MSAL (Microsoft Authentication Library) in EWS with Workplace365

Utilizing the MSAL (Microsoft Authentication Library) in EWS with Workplace365 Final July Microsoft introduced right here they might be disabling fundamental authentication in EWS on October 13 2020 which is now a bit of over a 12 months away. Given the period of time that has handed because the announcement any line of enterprise purposes or third celebration purposes that you just use that had been utilizing Fundamental authentication ought to have been modified or upgraded to help utilizing oAuth. If this is not the case the time to take motion is now.

When you should migrate a .NET app or script you may have utilizing EWS and fundamental Authentication you may have two Authentication libraries you possibly can select from

  1. ADAL – Azure AD Authentication Library (makes use of the v1 Azure AD Endpoint)
  2. MSAL – Microsoft Authentication Library (makes use of the v2 Microsoft Identification Platform Endpoint)
the commonest library you’ll come throughout in use is the ADAL libraries as a result of its been across the longest, has good help throughout a variety of languages and permits complicated authentications situations with help for SAML and many others. The MSAL is the most recent and best when it comes to its help for oAuth2 requirements and is the place Microsoft are investing their future improvement efforts. A great primer for understanding the distinction when it comes to the Tokens that each of those endpoint generate is to learn https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens
So which must you select ? In case your utilizing PowerShell then the ADAL is the simplest to make use of and there are a number of good examples for this like. Nonetheless from a long run viewpoint utilizing MSAL library is usually a more sensible choice as its going to supply extra supportability (new options and many others) going ahead so long as you do not fall into one in all  the restrictions described in https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Adal-to-Msal
On this publish I am going to have a look at utilizing the MSAL library with EWS to entry Mailboxes in Change On-line. 
Scopes

One of many greatest variations with regards to coding between the libraries with ADAL you specify the useful resource your going to make use of eg “https://outlook.office365.com” and with the MASL you particular the scopes you’ll use. With EWS its comparatively easy in that  there are solely two scopes (EWS does not can help you constrain your entry to completely different mailbox merchandise sorts) which you’d first want to permit in your Software registration which could be discovered within the Supported Legacy API’s part of the appliance registration(ensure you scroll proper to the underside)
Delegated Permissions

Software Permissions (the place you going to make use of AppOnly Tokens)
.default Scope

For v.1 apps you may get all of the static scopes configured in an software utilizing the .default scope so for ews that might look one thing like https://outlook.workplace365.com/.default . When your utilizing App Solely tokens this turns into essential.

App registration and Consent

One of many benefits of the MSAL library is dynamic consent which for EWS as a result of in apply your solely going to be utilizing one scope it does not have a lot use. Nonetheless in case your additionally going to be utilizing different workloads you perhaps in a position to benefit from that function. For the app registration you should use the v2 Endpoint registration course of (which is the default now within the Azure portal) see https://docs.microsoft.com/en-us/graph/auth-register-app-v2. This additionally makes it straightforward to deal with the consent inside a tenant.

Getting all the way down to coding

Within the ADAL there was just one single class known as the AuthenticationContext which you used to request tokens. Within the MSAL you may have the PublicClientApplication (which you utilize for traditional person authentication) and ConfidentialClientApp which will get used for AppOnly tokens and On-Behalf-Of circulate.

Endpoints 

With the v2 Endpoint you may have the choice of permitting

  1. frequent
  2. organizations
  3. shoppers
  4. Tenant particular (Guid or Identify)
For EWS you typically all the time wish to use the Tenant particular endpoint which implies its greatest to both dynamically get the TenantId for the tenant your focusing on or arduous code it . eg you may get the TenantId want with Three strains of C#

string domainName = "datarumble.com";
HttpClient Shopper = new HttpClient();
var TenantId = ((dynamic)JsonConvert.DeserializeObject(Shopper.GetAsync("https://login.microsoftonline.com/" + domainName + "/v2.0/.well-known/openid-configuration")
.Consequence.Content material.ReadAsStringAsync().Consequence))
.authorization_endpoint.ToString().Break up('/')[3];

In PowerShell you are able to do it with

$TenantId = (Invoke-WebRequest https://login.home windows.internet/datarumble.com/v2.0/.well-known/openid-configuration | ConvertFrom-Json).token_endpoint.Break up(‘/’)[3]

Delegate Authentication in EWS with MSAL and the EWS Managed API

This typically is the commonest manner of utilizing EWS the place your authenticating as a normal Person after which accessing a Mailbox. If its a shared Mailbox then entry will should be have granted by way of Add-MailboxFolderPermission otherwise you utilizing EWS Impersonation

That is the only C# instance of an Auth utilizing the MSAL library in a Console app to logon (the at the moment logged on person).

 string MailboxName = "[email protected]";
string scope = "https://outlook.workplace.com/EWS.AccessAsUser.All";
string redirectUri = "msal9d5d77a6-fe09-473e-8931-958f15f1a96b://auth";
string domainName = "datarumble.com";

HttpClient Shopper = new HttpClient();
var TenantId = ((dynamic)JsonConvert.DeserializeObject(Shopper.GetAsync("https://login.microsoftonline.com/" + domainName + "/v2.0/.well-known/openid-configuration")
.Consequence.Content material.ReadAsStringAsync().Consequence))
.authorization_endpoint.ToString().Break up('/')[3];

PublicClientApplicationBuilder pcaConfig = PublicClientApplicationBuilder.Create("9d5d77a6-fe09-473e-8931-958f15f1a96b")
.WithTenantId(TenantId);

pcaConfig.WithRedirectUri(redirectUri);
var TokenResult = pcaConfig.Construct().AcquireTokenInteractive(new[] { scope })
.WithPrompt(Immediate.By no means)
.WithLoginHint(MailboxName).ExecuteAsync().Consequence;

ExchangeService service = new ExchangeService(ExchangeVersion.Change2016);
service.Url = new Uri("https://outlook.workplace365.com/ews/change.asmx");
service.Credentials = new OAuthCredentials(TokenResult.AccessToken);
service.HttpHeaders.Add("X-AnchorMailbox", MailboxName);

Folder Inbox = Folder.Bind(service, WellKnownFolderName.Inbox);

AppOnly Tokens

That is the place your Software is authenticating utilizing a App Secret or SSL certificates, after this your App will get full entry to all Mailboxes in a tenant (it essential to not that the scoping function https://docs.microsoft.com/en-us/graph/auth-limit-mailbox-access does not work with the EWS so you should be utilizing the Graph or Outlook api).

 string clientId = "9d5d77a6-fe09-473e-8931-958f15f1a96b";
string clientSecret = "xxxx";
string mailboxName = "[email protected]";
string redirectUri = "msal9d5d77a6-fe09-473e-8931-958f15f1a96b://auth";
string domainName = "datarumble.com";
string scope = "https://outlook.workplace365.com/.default";

HttpClient Shopper = new HttpClient();
var TenantId = ((dynamic)JsonConvert.DeserializeObject(Shopper.GetAsync("https://login.microsoftonline.com/" + domainName + "/v2.0/.well-known/openid-configuration")
.Consequence.Content material.ReadAsStringAsync().Consequence))
.authorization_endpoint.ToString().Break up('/')[3];

IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(TenantId)
.WithRedirectUri(redirectUri)
.Construct();


var TokenResult = app.AcquireTokenForClient(new[] { scope }).ExecuteAsync().Consequence;
ExchangeService service = new ExchangeService(ExchangeVersion.Change2016);
service.Url = new Uri("https://outlook.workplace365.com/ews/change.asmx");
service.Credentials = new OAuthCredentials(TokenResult.AccessToken);
service.HttpHeaders.Add("X-AnchorMailbox", mailboxName);
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, mailboxName);
Folder Inbox = Folder.Bind(service, new FolderId(WellKnownFolderName.Inbox, mailboxName));



Token Refresh

One of many huge issues lacking within the EWS Managed API is a callback earlier than every request that checks for an expired Entry Token. As a result of tokens are solely legitimate for 1 hour in case you have an extended operating course of like a migration/export or information evaluation then you should just be sure you have some provision in your code to trace the expiry of the entry token and the refresh the token when wanted.

Doing this in PowerShell

In case your utilizing PowerShell you should utilize the identical code as above so long as import the MSAL library dll into your session

Some easy auth examples for this might be

 Delegate Authentication 

$MailboxName = "[email protected]";
$ClientId = "9d5d77a6-fe09-473e-8931-958f15f1a96b"
$scope = "https://outlook.workplace.com/EWS.AccessAsUser.All";
$redirectUri = "msal9d5d77a6-fe09-473e-8931-958f15f1a96b://auth";
$domainName = "datarumble.com";
$Scopes = New-Object System.Collections.Generic.Checklist[string]
$Scopes.Add($Scope)
$TenantId = (Invoke-WebRequest https://login.home windows.internet/datarumble.com/v2.0/.well-known/openid-configuration | ConvertFrom-Json).token_endpoint.Break up('/')[3]
$pcaConfig = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientId).WithTenantId($TenantId).WithRedirectUri($redirectUri)
$TokenResult = $pcaConfig.Construct().AcquireTokenInteractive($Scopes).WithPrompt([Microsoft.Identity.Client.Prompt]::By no means).WithLoginHint($MailboxName).ExecuteAsync().Consequence;


AppOnly Token

$ClientId = "9d5d77a6-fe09-473e-8931-958f15f1a96b"
$MailboxName = "[email protected]"
$RedirectUri = "msal9d5d77a6-fe09-473e-8931-958f15f1a96b://auth"
$ClientSecret = "xxx";
$Scope = "https://outlook.workplace365.com/.default"
$TenantId = (Invoke-WebRequest https://login.home windows.internet/datarumble.com/v2.0/.well-known/openid-configuration | ConvertFrom-Json).token_endpoint.Break up('/')[3]
$app = [Microsoft.Identity.Client.ConfidentialClientApplicationBuilder]::Create($ClientId).WithClientSecret($ClientSecret).WithTenantId($TenantId).WithRedirectUri($RedirectUri).Construct()
$Scopes = New-Object System.Collections.Generic.Checklist[string]
$Scopes.Add($Scope)
$TokenResult = $app.AcquireTokenForClient($Scopes).ExecuteAsync().Consequence;




Tags:

Related Posts

Leave a Reply