Integrating Office 365 web applications and add-ins with LOB applications using Azure API Apps


Connecting your Office solutions to LOB adds complexity and often requires server-side code. What if you could leverage Azure API Apps to connect your Single Page Applications to LOB?

When building Office 365 web application and Office web add-ins there is a chance your solution needs to connect not only to Office 365 but also to your line of business applications. Thanks to the Microsoft Graph we can build powerful client-side applications that communicate with Office 365. It’s communicating with LOB systems that adds complexity to our applications and often requires server-side code. What if we could reach these LOB systems from client-side applications similarly to how we connect to the Microsoft Graph?

Microsoft Graph support CORS. This allows us to build Single Page Applications that use only client-side code to communicate with Office 365. If the same application needs to use other APIs that don’t support CORS or the OAuth implicit grant often it is changed to be a server-side application and be able to communicate with APIs. The good news is that using Azure API Apps you can easily separate the APIs from your main application. This way your application remains a 100% client-side code based Single Page Application and the API App abstracts away all the details necessary to connect to your line of business applications.

Although you’re not required to use Azure API Apps to host your LOB APIs, they make it easy to enable CORS, required if you want to use them with your Single Page Applications, and to protect the API with Azure Active Directory.

To illustrate the scenario of building an Office 365 web application integrated with LOB, I used Mavention Hub: an organization portal that we build at Mavention which shows personal information from across all Office 365. Mavention Hub is an Office 365 web application built as an AngularJS Single Page Application that uses CORS and ADAL JS to connect to Office 365.

Mavention Hub

In this example we will extend Mavention Hub with the ability to show the latest news from the Mavention corporate website. The API that the Mavention website offers to retrieve the latest news can be used by anonymous users and doesn’t support CORS which is why it requires a server-side wrapper in order for it to be used in a Single Page Application.

Preparing the API

The API used to retrieve the latest news from the corporate Mavention website is a simple Node.js-based REST API that calls the API on the Mavention website and returns the contents of the latest press release as a JSON object.

Latest news from the corporate Mavention website retrieved by an API as a JSON object

This Node.js API is deployed to a standard Azure API App.

Azure API App with the API

We want this API to support CORS, so that we can call it directly from our Single Page Application, but also to be protected. Since it’s hosted on the Internet, we don’t want everyone to be able to call it. We will secure the API using Azure Active Directory. Only users authenticated with their organizational account will be able to use the API.

Enabling CORS in Azure API Apps

Enabling CORS in Azure API Apps is extremely easy and comes down to toggling a switch and specifying allowed origins.

To enable CORS for your API hosted in an Azure API App:

In the new Azure Management Portal navigate to your API App:

API App information blade displayed in the new Azure Management Portal

In the Settings blade, from the API group, click the CORS option.

CORS options highlighted in the Settings blade of an Azure API App

In the list of allowed origins enter all URLs that you allow to use the API. You can also enter an * (asterisk) to allow make the API available to all web applications.

Allowed origins configuration for an Azure API App

Save the changes by clicking the Save button on the toolbar. Without changing anything about the API we have just enabled CORS support and made the API available to Single Page Applications.

Securing the Azure API App with AAD

The next step is to secure the API. Similarly to Mavention Hub, we want the API to be accessible only by users authenticated using their organization account. Just like we were able to enable CORS, Azure API Apps can be secured with Azure Active Directory without changing anything in the API itself.

Azure API Apps are protected with AAD by associating them with an AAD application registration entry. This is the same entry that you need to allow your Office 365 web application or Office web add-in to connect to Office 365. The only difference is, that because your API connects to your LOB applications, rather than Office 365 or Azure, you don’t need to grant it any specific permissions. The application just need to be registered with AAD. Following is a sample registration page that allows you to secure your API with AAD:

AAD registration page for an API App

Azure API Apps can be secured with Azure Active Directory in two ways: express - which will create the necessary registration information for you in the default Azure Active Directory of your Azure subscription and advanced - where you can specify the AAD where your application registration information is stored yourself. If the API App and your organization AAD are located in the same Azure subscription you can choose the express configuration option. In all other cases you can use the advanced configuration mode.

To secure your API App with AAD:

In the new Azure Management Portal navigate to your API App:

API App information blade displayed in the new Azure Management Portal

On the Setting blade, from the Features group, click the Authentication / Authorization option:

Authentication / Authorization option highlighted on the Settings blade of an Azure API App

Enable authentication for your API App by switching the App Service Authentication toggle to On.

App Service Authentication option enabled for the Azure API App

Because we want to allow the API to be used only by users authenticated with their organization account, in the Action to take when request is not authenticated drop-down choose the Login with Azure Active Directory option.

The 'Login with Azure Active Directory' option highlighted in the 'Action to take when request is not authenticated' drop-down

The last thing that we need to do, is to link the API App with an application registration entry. To do this, in the Authentication Providers list, click the Azure Active Directory option.

'Azure Active Directory' option highlighted in the list of available Authentication providers

In the Azure Active Directory Settings blade, choose the management mode suitable for your scenario. In this example, because the API App is hosted in a different Azure subscription than where the AAD used to secure the API App is, we choose the Advanced mode and provide the Client ID and the Issuer Url ourselves.

Application registration information filled in on the 'Azure Active Directory Settings' blade

Confirm your changes by clicking the OK button on the Azure Active Directory Settings blade and clicking the Save button in the toolbar on the Authentication / Authorization blade.

Red arrows pointing to the OK button on the 'Azure Active Directory Settings' blade and the Save button on the 'Authentication / Authorization' blade

If you try to use the API now you will be prompted to authenticate using your organization account.

Azure login page displayed when trying to access the API App

Enabling OAuth implicit grant

Although the API App is now secured and can only be used by users authenticated using their organization account there is one more thing left to be done.

Since it’s an API that we are protecting, we cannot display a login page whenever the application needs to authenticate for accessing the API. Azure Active Directory solves this challenge using OAuth that we can use to get a valid access token by passing a secret. But because we’re working with a client-side application and cannot store secret, we have to enable the OAuth implicit grant for the API App.

To enable the OAuth implicit grant for the API App:

In the old Azure Management Portal navigate to your AAD and from the menu click the Applications option.

Red arrow pointing to the Application option in the old Azure Management Portal

In the list of applications, locate the entry associated with your Azure API App and open it.

Red arrow pointing to the application entry associated with the Azure API App

On the bottom of the page click the Manage Manifest button.

The 'Manage Manifest' button highlighted in the toolbar

From the menu click the Download Manifest option.

The 'Download Manifest' option highlighted in the menu

In the Download Manifest dialog click the Download manifest link to download the manifest of your application.

Red arrow pointing to the 'Download manifest' link in the 'Download Manifest' dialog

Open the downloaded manifest file in the text editor of your choice and locate the oauth2AllowImplicitFlow property. Change its value to true and save the changes.

The 'oauth2AllowImplicitFlow' setting configured to true in the application manifest

Back in the Azure Management Portal click the Manage Manifest button and this time in the menu click the Upload Manifest option.

The 'Upload Manifest' option highlighted in the menu

In the Upload Manifest dialog browse for the modified manifest file and upload it by clicking the checkbox button.

Having completed these steps our API is ready to be used in Mavention Hub.

Connecting the dots

Extending Mavention Hub with a secure API to show the latest news from the corporate Mavention website

In order for Mavention Hub to be able to use the newly configured API to show the latest news from the corporate Mavention website, there are a few things that we need to do.

First of all we need to grant the Mavention Hub application access to the API App. This has to do with the fact users don’t access the API directly but rather open Mavention Hub, authenticate using the organization account and using that information apply for a valid access token for the API.

Next, we have to register the API with ADAL JS so that every time Mavention Hub wil try to access it, ADAL JS will automatically retrieve a valid access token using the OAuth implicit grant.

Although both steps aren’t overly complex, there are some essential details in both of them. If you get them wrong you will waste a lot of time trying to figure out why you application isn’t working as expected.

Granting Mavention Hub permissions to access the API App

Mavention Hub is an Office 365 web application built as an AngularJS Single Page Application. To connect to Office 365 it uses ADAL JS with OAuth implicit grant. The way it’s structured, it resembles a lot Office add-ins connected to Office 365 created using the Yeoman Office Generator.

As every other application connecting to Office 365, Mavention Hub has an application entry registered in the AAD listing all the different permissions to Office 365 and Azure it needs to display relevant information to users.

Mavention Hub AAD application entry details displayed in the old Azure Management Portal

To allow Mavention Hub to access the API App that retrieves the latest news from the corporate Mavention website, the API App hosted the API has to be added to the list of permitted applications.

Essential detail #1: the following steps must be executed by the AAD admin. Even though users with restricted AAD administration permissions will be able to seemingly complete these steps, the web application will throw an AAD error trying to get a valid access token for the API.

To grant your web application access to your API:

On the application registration page scroll down to the Permissions to other applications section and click the Add application button.

Red arrow pointing to the 'Add application' button

In the Permissions to other applications dialog, open the Show drop-down, choose the All apps option and confirm your choice by clicking the checkbox button on the right.

The 'All apps' option highlighted in in the 'Permissions to other applications' dialog

In the list of all applications select the API App and confirm the choice by clicking the checkbox button in the lower right corner of the dialog window.

The API App selected in the 'Permissions to other applications' dialog window

In the list of delegated permissions choose the Access permission and confirm all changes by clicking the Save button.

The 'Access' permission higlighted in the delegated permissions drop-down

Having completed these steps Mavention Hub is now allowed to access the latest news API.

Registering the latest news API with ADAL JS configuration of Mavention Hub

Because the API responsible for retrieving the latest news from the corporate Mavention website is protected with Azure Active Directory, we need a valid access token to access it. Rather than retrieving it manually, we can have ADAL JS, which is already a part of Mavention Hub, retrieve it automatically for us.

In the code of your web application navigate to the configuration of endpoints for ADAL JS. By default it will look similarly to:

define(['app', 'utils'], function(app, utils) {
    app.config(['$httpProvider', 'adalAuthenticationServiceProvider', 'appId', 
        function($httpProvider, adalProvider, appId) {
        var adalConfig = {
            tenant: 'common', 
            clientId: appId, 
            extraQueryParameter: 'nux=1',
            endpoints: {
                'https://graph.microsoft.com': 'https://graph.microsoft.com',
            }
            //cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost. 
        };
    
        adalProvider.init(adalConfig, $httpProvider); 
    }]);
    
    return app;
});

In order for ADAL JS to automatically retrieve a valid access token to our API App we need to add it to the list of endpoints. The list of endpoints consists of dictionary entries, where the key defines the URL of the API and the value specifies the ID of the application for which the access token should be retrieved. ADAL JS uses an HTTP request interceptor and monitors all HTTP requests. Whenever a request is issued to a URL starting with a URL specified in the list of endpoints, ADAL JS will automatically retrieve a valid access token for the associated application.

Essential detail #2: where with registering Microsoft Graph or SharePoint Online endpoints you use URIs as the application ID, for registering your own applications, you need to use the Client ID instead. Using application ID doesn’t seem to work and returns a meaningless error that won’t help you fix your configuration.

define(['app', 'utils'], function(app, utils) {
    app.config(['$httpProvider', 'adalAuthenticationServiceProvider', 'appId', 
        function($httpProvider, adalProvider, appId) {
        var adalConfig = {
            tenant: 'common', 
            clientId: appId, 
            extraQueryParameter: 'nux=1',
            endpoints: {
                'https://graph.microsoft.com': 'https://graph.microsoft.com',
                'https://lob-api.azurewebsites.net': '36dc179e-b1c7-49ce-be8f-a140aec3c60d'
            }
            //cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost. 
        };
    
        adalProvider.init(adalConfig, $httpProvider); 
    }]);
    
    return app;
});

If you would navigate to Mavention Hub now you would see the latest press release displayed on top of the page using the newly configured Azure API App.

Latest news from the corporate Mavention website displayed in Mavention Hub

Summary

Microsoft Graph allows us to leverage modern techniques such as Single Page Applications, CORS and OAuth implicit flow to build powerful web applications and add-ins that connect to Office 365. Connecting to LOB adds complexity to the architecture of these solutions often requiring server-side code. By separating out connections to LOB to separate APIs deployed as Azure API Apps, you can leverage modern development techniques for building web applications and add-ins and connect to LOB in a secure fashion.

Others found also helpful: