Office 365 / EWS Authentication using OAuth

13,179

Solution 1

TokenCredentials is not the right class to use in this example. Like Jason mentioned put in place for other reasons. As a note and to clarify using this and/or SAML tokens will not work in Exchange Online with EWS. Only OAuth based access is supported. To make this work we put a OAuthCredentials class in EWS Managed API. In your code you can "var credentials = new OAuthCredentials(token)". Be aware that EWS Soap only supports full "user_impersonation" / "full access to the users mailbox" rights. Granular permission such as Calendar.Read are only available with EWS Rest APIs. While "Full mailbox access" requires an admin to consent, admins from other tenants can consent as it is a web app. In case you want to develop a native app, the app has to be directly registered in the app of the tenant it runs in order to use "Full mailbox access".

Solution 2

You can use OAuth to connect to EWS (as opposed to REST), however, it's not as smooth. EWS requires the special "Have full access to a user's mailbox" delegated permission in Azure Active Directory, which requires an administrator to register it. This permission also doesn't "travel" outside the organization, so there is no user-consent scenario for EWS. Essentially, the only scenario that this works for is an administrator registering the application for your own organization.

Check your app registration in Azure and make sure you have that permission assigned.

Assuming that you have the permission assigned, I've made this work in two ways.

  1. The simplest: Just add the token you get back to the request headers in an Authorization header, like so:

    ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
    string accessToken = GetAccessToken();
    if (!string.IsNullOrEmpty(accessToken))
        service.HttpHeaders.Add("Authorization", "Bearer " + accessToken);
    
  2. More complex: Implement your own credentials class that implements the ICredentials interface. Pass this class into the constructor of the Microsoft.Exchange.WebServices.Data.OAuthCredentials class, and assign the new OAuthCredentials object to the Url property of the ExchangeService object.
Share:
13,179

Related videos on Youtube

MichelZ
Author by

MichelZ

CIO of a Software Company headquartered in Switzerland with a passion for technology, especially in C#, ASP.NET, .NET and (Windows-) System Administration / Automation See my LinkedIn Profile for more Information

Updated on September 15, 2022

Comments

  • MichelZ
    MichelZ over 1 year

    I'm trying to log onto Office 365 Exchange Online using OAuth and EWS Managed API.

    I am able to use connect to the Office 365 Web API's (REST), so I do have a valid Token from the Active Directory Authentication Library (ADAL).

    Now, I'm trying to connect using EWS and TokenCredentials.

    The code is pretty easy, I think:

    public static ExchangeService ConnectToServiceWithImpersonation(string token)
    {
        var service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
    
        if (true)
        {
            service.TraceListener = new TraceListener();
            service.TraceFlags = TraceFlags.All;
            service.TraceEnabled = true;
        }
    
        var credentials = new TokenCredentials(token);
    
        service.Credentials = credentials;
    
        service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
        return service;
    }
    

    The token is generated by ADAL, which in turn is from sample code using the "Office 365 API Tools - Preview"

    // Obtain information for communicating with the service:
    Office365ServiceInfo serviceInfo = Office365ServiceInfo.GetExchangeServiceInfo();
    if (!serviceInfo.HasValidAccessToken)
    {
        return Redirect(serviceInfo.GetAuthorizationUrl(Request.Url));
    }
    
    // Connect to Exchange
    var service = ConnectToServiceWithImpersonation(serviceInfo.AccessToken);
    
    Folder inbox = Folder.Bind(service, WellKnownFolderName.Inbox);
    

    On the Folder.Bind call, I get a 401 Unauthorized error. EWS Trace gives me this:

    2014-04-06 12:06:39.2012 TRACE ExchangeWebServices: EwsResponseHttpHeaders -> <Trace Tag="EwsResponseHttpHeaders" Tid="11" Time="2014-04-06 10:06:39Z">
    HTTP/1.1 401 Unauthorized
    request-id: 01ba1ca9-2850-480a-9d65-ec55bfef8657
    X-CasErrorCode: BadSamlToken
    X-FEServer: AMSPR04CA018
    Content-Length: 0
    Cache-Control: private
    Date: Sun, 06 Apr 2014 10:06:39 GMT
    Server: Microsoft-IIS/7.5
    WWW-Authenticate: Basic Realm=""
    X-AspNet-Version: 4.0.30319
    X-Powered-By: ASP.NET
    

    Unfortunately, hours of googling did not really help, there does not seem to be very much specific information about EWS and OAuth authentication, and I have no idea how to further troubleshoot it, so I'm hoping that anyone has some advice on how to get it working.

  • MichelZ
    MichelZ about 10 years
    The "Have full access to user's mailbox (preview)" is assigned. Yes, I know that it requires administrator permission, this is OK. The App will be operated by Admins only, it's not an end-user app.
  • Jason Johnston
    Jason Johnston about 10 years
    Ah ok. Then I suspect that the TokenCredentials class isn't doing the right thing. Have you looked at a network trace and confirmed that the token is being sent in the Authorization: Bearer header?
  • MichelZ
    MichelZ about 10 years
    I have not. I'll see that I can capture a trace and get back to you
  • Jason Johnston
    Jason Johnston about 10 years
    I looked into that TokenCredentials class, and it is not the way to go. That class was added a while back to support SAML tokens, not OAuth. I'll refine my answer above with further info.
  • MichelZ
    MichelZ about 10 years
    Just FYI: The Fiddler trace showed that it is not using the token in an Authorization: Bearer header, but it's part of the EWS request itself. (or the SOAP header to be exact)