Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to authenticate with OAuth to access EWS APIs

My web service is currently doing basic username/password authentication in order to subscribe the exchange user for receiving the events (like new mail event etc) like below:

var service = new ExchangeService(exchangeVersion)
                                  {
                                      KeepAlive = true,
                                      Url = new Uri("some autodiscovery url"),
                                      Credentials = new NetworkCredential(username, password)
                                  };

var subscription = service.SubscribeToPushNotifications(
                                    new[] { inboxFolderFoldeID },
                                    new Uri("some post back url"),
                                    15,
                                    null,
                                    EventType.NewMail,
                                    EventType.Created,
                                    EventType.Deleted,
                                    EventType.Modified,
                                    EventType.Moved,
                                    EventType.Copied);

Now, I am supposed to replace the authentication mechanism to use OAuth protocol. I saw some examples but all of them seem to be talking about authenticating the client (https://msdn.microsoft.com/en-us/library/office/dn903761%28v=exchg.150%29.aspx?f=255&MSPPError=-2147217396) but nowhere I was able to find an example of how to authenticate an exchange user with OAuth protocol. Any code sample will help a lot. Thanks.

like image 950
tavier Avatar asked Jul 31 '17 12:07

tavier


People also ask

How do I authenticate here APIs using OAuth?

Generating HERE OAuth Credentials To make HERE OAuth API requests, you will need to generate an “access token”. To generate access tokens, you will first need to generate HERE OAuth Credentials from the developer.here.com portal. Go to developer.here.com and login with your credentials.

What authentication does EWS use?

Basic authentication is no longer supported for EWS to connect to Exchange Online. Use OAuth authentication in all your new or existing EWS applications to connect to Exchange Online. OAuth authentication for EWS is only available in Exchange Online as part of Microsoft 365.


2 Answers

It's not clear what you mean with 'web service' and how you currently get the username and password. If that is some kind of website where the user needs to login or pass credentials, then you'll have to start an OAuth2 grant from the browser as in redirecting the clients browser to the authorize endpoint to start implicit grant or code grant. The user will be presented a login screen on the OAuth2 server (and not in your application), once the user logs in a code or access token (depending on the grant) will be returned to your application which you can use in the ExchangeService constructor.

If that 'web' service is some service that runs on the users computer you can use one of the methods described below.

Get AccessToken using AuthenticationContext

The example seems to be based on an older version of the AuthenticationContext class.

The other version seems to be newer, also the AcquireToken is now renamed to AcquireTokenAsync / AcquireTokenSilentAsync.

No matter which version you're using, you will not be able to pass username and password like you're doing in your current code. However, you can let the AcquireToken[Async] method prompt for credentials to the user. Which, let's be honest, is more secure then letting your application deal with those user secrets directly. Before you know, you'll be storing plain text passwords in a database (hope you aren't already).

In both versions, those methods have a lot of overloads all with different parameters and slightly different functionality. For your use-case I think these are interesting:

  • New: AcquireTokenAsync(string, string, Uri, IPlatformParameters) where IPlatformParameters could be new PlatformParameters(PromptBehavior.Auto)
  • Old: AcquireToken(string, string, Uri, PromptBehavior where prompt behavior could be PromptBehavior.Auto

Prompt behavior auto, in both vesions, means: the user will be asked for credentials when they're not already cached. Both AuthenticationContext constructors allow you to pass a token-cache which is something you can implement yourself f.e. to cache tokens in memory, file or database (see this article for an example file cache implementation).

Get AccessToken manually

If you really want to pass in the user credentials from code without prompting the user, there is always a way around. In this case you'll have to implement the Resource Owner Password Credentials grant as outlined in OAuth2 specificatioin / RFC6749.

Coincidence or not, I have an open-source library called oauth2-client-handler that implements this for use with HttpClient, but anyway, if you want to go this route you can dig into that code, especially starting from this method.

Use Access Token

Once you have an access token, you can proceed with the samples on this MSDN page, f.e.:

var service = new ExchangeService(exchangeVersion)
                  {
                      KeepAlive = true,
                      Url = new Uri("some autodiscovery url"),
                      Credentials = new OAuthCredentials(authenticationResult.AccessToken))
                  };
like image 78
huysentruitw Avatar answered Oct 22 '22 13:10

huysentruitw


In case someone is still struggling to get it to work. We need to upload a certificate manifest on azure portal for the application and then use the same certificate to authenticate the client for getting the access token. For more details please see: https://blogs.msdn.microsoft.com/exchangedev/2015/01/21/building-daemon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow/

like image 42
tavier Avatar answered Oct 22 '22 14:10

tavier