in Office 365 API, Visual Studio, VS2013

Changes to Office 365 API Authentication Library in the Summer Update

UPDATE: Office 365 API Tool is now included with Office Developer Tools and brings breaking changes to the Office 365 API Authentication Library. Please refer to the following post for updated content:

Update to Office 365 API Tools and Client Libraries

Today we released the Office 365 API Preview Tool summer update. The previous release of Office 365 client libraries (which are also still in preview) included the initial release of the Office 365 API authentication library which was built on top of the Active Directory Authentication Library (ADAL).

Based on your feedback we have improved the interoperability of the Office 365 API authentication library with ADAL to work well with other Azure-based services.

UPDATE: Office 365 API Tool is now included with Office Developer Tools and brings breaking changes to the Office 365 API Authentication Library. Please refer to the following post for updated content:

Update to Office 365 API Tools and Client Libraries

Today’s update brings a breaking change to the code required to authenticate with Office 365 APIs. For non-Xamarin-based applications, the new authentication flow is as follows (for Xamarin, continue to use the previously-documented flow):

1. Create the Office 365 Discovery Context

DiscoveryContext discoveryContext = await DiscoveryContext.CreateAsync();

The code above initializes the authorization context with app client-id, secret and authorization API loading them from appropriate configuration files.

2. Authenticate using Resource Id or Discovery Service

Using Resource Id:

ResourceDiscoveryResult dcr  = await discoveryContext .DiscoverResourceAsync(ServiceResourceId);

The code above will obtain the Tenant Id and also gets the currently logged on user Id. Using the tenant Id, you will be able to query the AAD Graph API.

Using Discovery Service:

CapabilityDiscoveryResult dcr = await discoveryContext.DiscoverCapabilityAsync("Contacts");

The code will either obtain authorization for using discovery service and call it to get the corresponding Service Endpoint URI and Resource Id or load this information if it was previously cached.

Whether using the discovery service or resource Id, the library will check if you already have a refresh token, if not, it will display the authorization page to sign in.

3. Create the respective client object and pass in a delegate to retrieve the access token

Func<Task<String>> getAccessToken = async () => 
{ 
UserIdentifier userId = new UserIdentifier(dcr.UserId, UserIdentifierType.UniqueId); 

string clientId = discoveryContext.AppIdentity.ClientId; 

AuthenticationResult authResult =  await discoveryContext 
          .AuthenticationContext 
          .AcquireTokenSilentAsync(ServiceResourceId, clientId, userId); 

return authResult.AccessToken; 
}; 

ExchangeClient exchangeClient = new ExchangeClient(ServiceEndpointUri, getAccessToken);

The code gets the access token for the specified service by calling the AcquireTokenSilentAsync method, which relies on a persistent cache to retrieve and renew access token as necessary without prompting the user to sign in.

Authenticating in ASP.NET MVC Web Applications

UPDATE: Office 365 API Tool is now included with Office Developer Tools and brings breaking changes to the Office 365 API Authentication Library. Please refer to the following post for updated content:

Update to Office 365 API Tools and Client Libraries

For MVC web applications, there is an extra step required as during the handling of the authentication, your application may throw a Redirect Required exception where you need to redirect your browser to the URL specified in the exception (which will be your registered redirect URI in the Azure Active Directory Application with additional query string parameters).

You must handle this exception by explicitly catching this RedirectRequired exception in a try/catch block:

try
{
    var contacts =
        ContactsAPISample.GetContacts();
}
catch (RedirectRequiredException ex)
{
    return Redirect(ex.RedirectUri.ToString());
}

As always, feel free to leave your comments if you have any questions or feedback.

UPDATE: Office 365 API Tool is now included with Office Developer Tools and brings breaking changes to the Office 365 API Authentication Library. Please refer to the following post for updated content:

Update to Office 365 API Tools and Client Libraries

Write a Comment

Comment

Time limit is exhausted. Please reload the CAPTCHA.

24 Comments

  1. Great to see the new update. But, this update still does not consist all the required properties and methods for accessing the “MyFilesApi”. MyFilesApi does not contain any relationship between the IFolder and IFile. How do we identify a specific file’s parent Folder? Are there any samples for “MyFiles” CRUD operations using the Office 365 API Tools Preview using Asp.Net MVC?

    • Hi Venkat, I am working on CRUD samples for every service. I should have something by next week. I will get back to you on your specific MyFiles query.

      • Hey, I’ve seen your presentation on Windows Store App “EmpOnBoard”. I am trying to build a similar kind of application in ASP.Net MVC. Is there a similar sample for ASP.Net MVC? Thanks.

      • Sorry to bother you again. How do we create 2 clients in a single instance? One SharePointClient for “OneDrive” and another SharePointClient for “Sites”.

        • Create member variables for discovery context and the clients you want to use. Then you can use the following pattern:

          if (_discoveryContext == null)
          {
          _discoveryContext = await DiscoveryContext.CreateAsync();
          }

          var dcr = await _discoveryContext.DiscoverResourceAsync(ExchangeServiceResourceId);

          _lastLoggedInUser = dcr.UserId;

          _exchangeClient = new ExchangeClient(ExchangeServiceEndpointUri, async () =>
          {
          return (await _discoveryContext.AuthenticationContext.AcquireTokenSilentAsync(ExchangeServiceResourceId, _discoveryContext.AppIdentity.ClientId, new Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier(dcr.UserId, Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifierType.UniqueId))).AccessToken;
          });

          _aadGraphClient = new AadGraphClient(new Uri(AadServiceEndpointUri, dcr.TenantId), async () =>
          {
          return (await _discoveryContext.AuthenticationContext.AcquireTokenSilentAsync(AadServiceResourceId, _discoveryContext.AppIdentity.ClientId, new Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier(dcr.UserId, Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifierType.UniqueId))).AccessToken;
          });

  2. Hi Chaks,

    i saw today your Channel9 Vid about Office365, is it possible to get the sample project which you are using there, to discover how you get things done?

    Greetings
    Lars

      • Hi Chaks, thanks for sample application.

        I encountered another Problem with the Authentication maybe you have an idea. From what i know, the TokenCache should be outlive the lifecycle of an application. So if i restart my application i should stay logged in without being prompted again.

        I always get the a prompt asking to consent the access rights. At the same time i get an exception which tells me that “AcquireTokenSlientAsync failed and its going to use AcquireToken instead”. Do u have any idea why it behaves like this and maybe how to fix this?

        Greetings
        Lars

        • There is a bug in the Office 365 DiscoveryContext that results in asking to consent every time the user signs in, but it is already fixed internally. So the next update will include this fix.

          For the latter, I am not sure why. Are you sure you are using DiscoverResourceAsync or DiscoverCapabilityAsync method before calling the AcquireTokenSilentAsync? The silent async means you are signed in already.

  3. Yes iam using DiscoverResourceAsync or DiscoverCapabilityAsync before creating the client which is going to aquire an access token in its constructor.

    Something like this:

    var cdr = await _discoveryContext.DiscoverCapabilityAsync(MyFilesCapability);

    _sharepointClient = new SharePointClient(cdr.ServiceEndpointUri, async () => (await _discoveryContext.AuthenticationContext.AcquireTokenSilentAsync(cdr.ServiceResourceId, _discoveryContext.AppIdentity.ClientId, new UserIdentifier(cdr.UserId, UserIdentifierType.UniqueId))).AccessToken);

  4. Hi Chaks,

    I am trying to develop a custom authentication module in .Net to allow users to access the O365 Site. For Ex, In the custom login page, the user enters <> and password & the module appends the domain to <> [or perform other changes to the <>] and authenticates the users by connecting to O365. Once the user is authenticated, we want to open the O365 site to the user without asking him to enter his credentials again. Will you be able to direct me on how to proceed with the requirement? Your help is much appreciated. Thanks.

  5. Hi Chaks,

    why is the lib throwing an exception instead of allowing to predefine something like distcoveryContext.AllowRedirect = true or someting similar. I think exception are too time intensive and depending on the kind of website you’re building (think about dashboards with multiple “parts” that all consume o365 APIs) you’ve to wrap all! the calls by a try/catch.

    Just my cents

  6. How does authentication for Office 365 work with Windows Phone 8.0+ using these APIs? Or is that not a supported scenario as of now?

    • The tool currently supports only Windows Phone 8.1 Store projects. The SDKs will support the WP 8.1 Store projects in the next update.

      Unfortunately, there is no support for Windows Phone 8.0 or Windows Phone 8.1 Silverlight projects.

  7. Hi Chaks,

    I am trying to get Emails of an User. But when I use above described code then code does not execute after

    var dcr = await _discoveryContext.DiscoverResourceAsync(ServiceResourceId);

    and throws exception “The browser must be redirected to a new URL” finally in caller function. I am able to get exchange client successfully by below code.

    ExchangeClient exchangeClient = new ExchangeClient(new Uri(ServiceEndpointUri), getAccessToken);

    Note: “getAccessToken” is same function as you described above.

    Please help on this.

    Thanks

  8. For me it hangs on this line of code:
    await DiscoveryContext.CreateAsync();

    Using dotPeek I see the CreateAsync method is just:
    await Task.Run((Action)(() => { }));
    return new DiscoveryContext();

    Can you change it to:
    return Task.FromResult(new DiscoveryContext());

    As that works for me, for now I can use “new DiscoveryContext()”. This is on “0.1.1-alpha” of “Microsoft.Office365.OAuth.AspNet”.

      • I just put the code back and DiscoveryContext.CreateAsync is now working for me so don’t know what happened. It’s a MVC app and is being called in a controller action. It didn’t make sense to me why `DiscoveryContext.CreateAsync` or `Task.Run((Action)(() => { }))` never completed, other async methods in the same controller action completed fine. I guess you can ignore my comment.

Webmentions

  • Office 365 API Client Libraries – Authenticating your client to Office 365 – Chaks Corner November 2, 2014

    […] Changes to Office 365 API Authentication Library in the Summer Update […]