An Architecture for SharePoint Apps That Call Other Services
This post will show an architecture for a SharePoint provider hosted app that calls other services such as the O365 API for Exchange, Azure AD Graph API, PowerBI API, or a custom Web API.
Background
This post is part of a series on building a SharePoint app that communicate with services protected by Azure AD.
- Part 1 - An Architecture for SharePoint Apps That Call Other Services (this post)
- Part 2 - Using OpenID Connect with SharePoint Apps
- Part 3 – Call O365 Exchange Online API from a SharePoint App
- Part 4 – A Sample SharePoint App That Calls a Custom Web API
- Part 5 - The API Economy: Consuming Our Web API from a Single Page App
I have been asked several times lately how a SharePoint provider hosted app can access other services such as Exchange Online API, PowerBI API, or the Azure AD Graph API. This post will propose an architecture for how you to create a SharePoint provider-hosted app that calls services protected by Azure AD. We will also discuss the benefits of this architecture. I’m not going to show any code yet, we’ll get to that in an upcoming post. For now, let’s agree on an approach.
Why Can’t I Just Use the SharePoint Access Token?
I’ve had this discussion with numerous developers. If it’s all just OAuth, can’t I just use the access token that SharePoint gives me to call Exchange? The answer is no. When you create a new provider-hosted app using Visual Studio 2013, you are prompted to choose between a low-trust app or a high-trust app. When creating a low-trust app, you choose the option to use Windows Microsoft Azure Access Control Service.
This enables our app to request an OAuth access token from Azure ACS to present to SharePoint Online. This app is used for a very specific purpose: extending SharePoint. This includes things like remote event receivers and deploying content to a SharePoint app web. When the SharePoint app model was created, the Azure AD capability of issuing OAuth tokens wasn’t complete yet, hence why the current implementation relies on Azure ACS.
If I create my SharePoint provider-hosted app, run the application, and decode the OAuth token using a tool like my Fiddler extension that decodes OAuth tokens, I can see that the issuer is Azure ACS and the audience is SharePoint.
The “aud” claim is the audience claim, indicating the audience intended for this access token. Each access token is specific to an audience. In this case, the audience for this token is <“00000003-0ff1-ce00-000000000000/kirke3.sharepoint.com@03fb46a-1140-4514-89xxxxxxxxx>”.
It is true that Azure Active Directory also enables the ability to register applications so that you can request an OAuth access token.
The token issued by Azure AD is not the same token as the one issued by Azure ACS, they differ by the claims they contain. To show this, I used a different application (using the sample WebAPI-OnBehalfOf-DotNet on GitHub) and I decode the access token request to Graph API. I see that the issuer is different.
More importantly, the audience claim is different. The audience claim in this token is “https://graph.windows.net”, which is the Azure AD Graph API. Tokens are intended to access a resource identified by the “aud” claim.
Even though there is an Azure Active Directory implementation behind O365, the current implementation of SharePoint provider hosted apps does not use Azure AD to issue OAuth tokens, it uses Azure ACS. We have an issuer mismatch problem and the token issued by ACS cannot be used to call a different service that expects a token issued by Azure AD. More importantly, each token is intended for a specific resource identified by the “aud” claim. I show an example of this in the post Call O365 Exchange Online API from a SharePoint App where we have four different access tokens for four different resources.
One more thing to point out… the set of claims in the SharePoint app token is different than the set of claims in the Azure AD Graph API token. There are claims in a SharePoint app token that are specific to supporting SharePoint apps, specific claims that SharePoint requires in order to identify and process the request correctly such as the “identityprovider” claim. I go into grave detail on this in the post High Trust SharePoint Apps on Non-Microsoft Platforms.
A Tale of Two Tokens
We really need two tokens: one to call SharePoint using the app model (the one that uses Azure ACS), and a second one to call a service protected using Azure AD, such as the O365 Exchange API.
The access token issued by ACS is needed for provider hosted apps to facilitate things like remote event receivers. The access token issued by Azure AD enables us to call services protected by Azure AD, such as the Office 365 Exchange Online API. We’re not reusing the SharePoint app’s token to call other services, there are two distinct tokens.
As mentioned in a previous blog post, Calling O365 APIs from your Web API on behalf of a user, we could introduce a custom Web API endpoint. This opens up even more possibilities because we can delegate tokens on behalf of the current user, enabling us to delegate access. Instead of our app just being a website that calls another service, we can leverage the much broader ecosystem that Azure Active Directory enables.
The Value of an API
Taking it a step further… now that we have a Web API, we can now expose that to multiple types of clients. Those clients might be a web site written with PHP, Node.js, Java, or .NET, it might be a native client application, or it could be a multi-device hybrid application written with the new Cordova tooling in Visual Studio.
By changing our perspective of the problem, our SharePoint provider-hosted app becomes just another client that calls our custom Web API that is protected by Azure AD. It just so happens to also call SharePoint using the token issued by Azure ACS to do some SharePoint-specific extensions. I highlight the provider-hosted app below.
The key to making all of this work seamlessly for the end user is to change your app to authenticate against the same directory that you are using for O365. An example of doing this is provided online, WebApp-WebAPI-OpenIDConnect-DotNet. When the user accesses your application, they would authenticate against Azure AD and obtain an access token. The very best part is that the end user doesn’t have to actually type in their credentials: because they have already authenticated against Azure AD when they accessed the O365 site, the same authentication cookie is used and the user is silently authenticated with your provider hosted app.
We’ll show an example of how to do this, but hopefully I’ve got you excited enough to see why this is so cool.
For More Information
WebAPI-OnBehalfOf-DotNet – sample for Azure AD that shows how to call a service on behalf of the caller
OAuth Fiddler Extension – extension for Fiddler that enables you to inspect OAuth tokens.
Calling O365 APIs from your Web API on behalf of a user – details on how to create a Web API that calls other services on behalf of the current user
WebApp-WebAPI-OpenIDConnect-DotNet – sample for Azure AD that shows how to protect a web application using OpenID Connect and a Web API using Azure AD bearer authentication.
Comments
Anonymous
March 26, 2015
But we actually can use access token acquired from the Azure AD to make requests to the SharePoint online. samlman.wordpress.com/.../using-adal-access-tokens-with-o365-rest-apis-and-csomAnonymous
March 26, 2015
@Sergei - yes, and I was going to address that in an upcoming post :) There are still reasons why this approach is required, specifically for those APIs that the O365 SharePoint Online API does not yet expose such as workflow APIs. Further, Steve's post proves my point. There is a misconception by developers that you can somehow magically reuse an access token to access other services, the most popular being Exchange. Steve's post shows how to do basically the same thing I am doing here, obtaining an access token to a specific resource. The fact that you can use CSOM with an AAD access token doesn't change the fact that you need one token per resource. Finally, there can be tremendous value in creating your own consumable APIs that perform data transformation and augmentation instead of putting that burden on the client devices and replicating that logic.Anonymous
May 19, 2015
The comment has been removed