As is evident from my last post, I am currently working with the Windowz Azure cloud as a hosting platform for a single page application based on React.js.

One of the first issues that popped up (beyond deploying static code) was how to set up CORS from this static site to an Azure-hosted API. This is relatively easy, but involves the adal.js library which is scarciliy documented. Below is detailed what is necessary to get this to work properly.

Azure portal set up

The first step is to go the Azure Web Portal (the new one) and go into the settings for your Web API. Here go to the CORS panel and add your public domain and a localhost domain for testing purposes (You can set up more fine-grained rules for CORS-requests using C#).

The azure CORS control panel, screenshot.
Make sure your domain (and `localhost` for testing) is in this list.

Once that is done, you need to get the adal.js library from github. You want the non-angular adal.min.js. Download this and link it to your project using either import or a script tag depending on your setup.

You then need to set up Active Directory for you web app. The details of doing so are listed on this Microsoft Support page, I won’t go into the exact server-side setup of this here.

Set up the AuthenticationContext

Once that is done, you can hook up the JavaScript frontend using adal.js. First you need to create the AuthenticationContext, which is the global instance for the authenticated entitiy. This should always be initialized on page load.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Set up the ADAL instance, we will use the throughout the app
var adalInstance = new AuthenticationContext({
  instance: 'https://login.microsoftonline.com/',
  
  // The client ID of the app from the Azure Portal
  clientId: 'aabbccee-aabb-1122-3344-556677889900',
  
  // Where do we want to go after logging out
  postLogoutRedirectUri: window.location.origin, 
  
  endpoints: {
    // The domain of API (requsets are made TO)
    // And the same client id as above
    "https://YOURAPIDOMAIN.azurewebsites.net/": "aabbccee-aabb-1122-3344-556677889900" 
  }
})

To run on page load

When the page loads, you need to see if we have been redirected from the Active Directory login page, you do this be checking isCallback on the URL hash.

This should be done on every page load after initializing the AuthenticationContext above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// If this returns true, the user is logged in
function authenticateToken() {
    if (adalInstance.getCachedUser()) {
        // If we have a cached login, use it
        return true
    }

    if (adalInstance.isCallback(window.location.hash)) {
        // This happens after the AD login screen,
        // handleWindowCallback will use the hash to
        // complete the login
        adalInstance.handleWindowCallback()
        return true
    }

    // Not logged in
    return false
}

if (authenticateToken()) {
    // User is logged in
}
else {
    // Not logged in, go to 401 page?
    window.location.pathname = '/401.html'
}

You need to call authenticateToken once on page load to make the login process functional.

To run when you want to log in and out

To trigger the login page, or to logout from the service. Use the following two functions:

1
2
3
4
5
// Will go to the Active Directory login page, and redirect back on successful login
adalInstance.login()

// Destroy all cookies, and redirects back to `postLogoutRedirectUri` in the AuthenticationContext config above
adalInstance.logOut()

To make authenticated CORS requests to Azure

This is what we have been waiting for, making authenticated cross-site requests to the Azure-hosted API. In this example I’m using the new standard fetch API.

What you need to do is call getCachedToken on your AuthenticationContext, this will return a bearer token you can attach to the request under the Authorization header.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function azureApiRequest(method, resource, body) {
    var resourceUrl = apiUrl + resource;
    
    // Use the client ID of your app for this call,
    // same as in the configuration earlier
    var bearerToken = adal.getCachedToken('aabbccee-aabb-1122-3344-556677889900')
   
   var opts = {
        method: method,
        headers: {
            'Authorization': 'Bearer ' +  bearerToken
        }
    }

    // I'm using JSON for my API, you can change this to your
    // heart's desire
    if (body) {
        opts.body = JSON.stringify(body)
        opts.headers['Content-Type'] = 'application/json'
    }

    return fetch(resourceUrl, opts)
        .then(response => {
            return response.json()
        }).catch(function(error) {
            console.log("Network problem: " + error)
            // Inspect the error further to see what is actually wrong
        }
    )
}

azureApiRequest('GET', '/Info').then(
    appInfo => console.log("Received: " + JSON.stringify(appInfo))
)

Hope this will be of help to other people struggling with getting this to work. The quality of Microsoft’s documentation is overall very low in my opinion, while they do have a lot of documentation it is often outdated or unnecessarily detailed. I seldom feel the people who wrote the documentation actually used the API in question.