1
votes

I'm still struggling with this. Please see my previous question for details.

I am doing an application (currently command line) which should access Office 365/Exchange through EWS Managed API. The goal is to authenticate through OAuth2.

I have registered an application in Azure AD.
I have used the ClientID from there
I generated an App Secret / Key
I have delegated the "Have full access to a users' mailbox (preview)" permissions to the App.

I am using ADAL to retrieve the Access Token like this:

var authority = "https://login.windows.net/<tenant>"
var authContext = new AuthenticationContext(authority);
var clientCredential = new ClientCredential("<clientId>", "<appKey>");
result = OAuthTokenManager.authContext.AcquireToken("<my ResourceID>", clientCredential);

I do get an access token back. The decoded value is:

{
 "typ": "JWT",
 "alg": "RS256",
 "x5t": "kriMPdmBvx68skT8-mPAB3BseeA"
}.
{
 "aud": "<my resource ID>",
 "iss": "https://sts.windows.net/2d1f889d-7930-4ef6-9f87-ef096d91ac47/",
 "nbf": 1403253608,
 "exp": 1403296808,
 "sub": "bdb0baf9-29ca-4a43-b9f8-d81ca2ae83bd",
 "appid": "<my app ID>",
 "oid": "bdb0baf9-29ca-4a43-b9f8-d81ca2ae83bd",
 "tid": "2d1f889d-7930-4ef6-9f87-ef096d91ac47",
 "idp": "https://sts.windows.net/2d1f889d-7930-4ef6-9f87-ef096d91ac47/"
}.
[signature] 

I then use this token to connect to EWS:

var service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
var credentials = new OAuthCredentials(token);
service.Credentials = credentials;
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "<smtp address of o365 mailbox>");
Folder inbox = Folder.Bind(service, WellKnownFolderName.Inbox);

The Folder.Bind fails with a 401 error.

In EWS Trace I can see this as the reason:

The audience claim value is invalid <my resource ID>

The resource ID is the "APP-ID-URI" from the registered application.

I'm sure I'm only missing a small details... but I can't find it :)
Any pointers are much appreciated.

If I use https://outlook.office365.com/ as resource ID (aud), I get this error message:

ACS50001: Relying party with identifier 'https://outlook.office365.com/' was not found.

The Tenant does have an Exchange subscription, and it has full access to the mailbox.

2

2 Answers

1
votes

Ah ok. With a service-type app, you're going to want to use a service account that can impersonate your users. See this MSDN topic for details. Once you have that account, you'll want to authenticate via OAuth as that service account, then impersonate your users as needed.

With a native application, you cannot use the app secret to authenticate. So you'll need to do something like:

AuthenticationResult result = authContext.AcquireToken("https://outlook.office365.com", clientId, new Uri(callbackUri), PromptBehavior.Auto);

Where clientId is your client ID from your Azure registration, and callbackUri is the redirect URI you specified when registering your app in Azure. This will cause a prompt window to show, but if you save the token and refresh token and use those to refresh, you should avoid any further prompts. The token you get back should look something like:

{
 "typ": "JWT",
 "alg": "RS256",
 "x5t": "kriMPdmBvx68skT8-mPAB3BseeA"
}.
{
 "aud": "https://outlook.office365.com",
 "iss": "https://sts.windows.net/9e4563d1-423e-493b-bdc5-9a98fe2e24d9/",
 "iat": 1403706230,
 "nbf": 1403706230,
 "exp": 1403710130,
 "ver": "1.0",
 "tid": "9e4563d1-423e-493b-bdc5-9a98fe2e24d9",
 "amr": [
  "pwd"
 ],
 "oid": "4a6e20e6-9711-4ca1-888b-34e63f65f897",
 "upn": "[email protected]",
 "unique_name": "[email protected]",
 "sub": "Pp3JW2dfYELMUBjGjUIZLarT4diOkkKZ1OJPVunzAYE",
 "puid": "100300008A9245F4",
 "family_name": "Account",
 "given_name": "Application",
 "appid": "<your app id>",
 "appidacr": "0",
 "scp": "user_impersonation",
 "acr": "1"
}.
[signature]

The app will authenticate as the [email protected] user, and then you can impersonate other users. I just tested this with my test Office 365 account using a little test console app.

One last final caveat: the OAuth permission scope required for EWS are not portable like the other permission scopes are. What I mean by that is that unlike a REST API app, where you can register it in Azure using your developer tenant, and then other Office 365 organizations can just consent to your app, EWS apps that use OAuth have to be registered separately in each tenant that uses them. If you're creating this app for your own organization, not so big a deal. But if you were planning on licensing this app to other organizations, something you should be aware of.

0
votes

Your "aud" parameter should be "https://outlook.office365.com". Try passing that to AcquireToken. You also shouldn't need to set ImpersonatedUserId. Hope that helps!