Extending SharePoint with ADAL and the Microsoft Graph API – Part 2 (The Authorization)

This entry is part 2 of 3 in the series Extending SharePoint with ADAL and the Microsoft Graph API

Introduction

In Part 1 of this series I covered all the setup needed to start your Microsoft Graph API (MSGraphAPI) client side widget. In Part 2, we’re going to dive into the many ways to use adal.js and its counterpart adal-angular.js. I’ve included the same resources I included in Part 1, under the section for ADAL you’ll find a lot of references to Cloud Identity blog by Vittorio Bertocci a Principal Program Manager at Microsoft who has blogged extensively on the library, explaining in depth the technical workings of it. I encourage you to read those posts I’ve included below to get a complete understanding of the library. Also, included in the references is a post about utilizing ADAL in the SharePoint Framework (SPFx). As is, ADAL was never meant to be used as part of a widget architecture as ADAL isn’t a singleton, so if you have multiple web parts on your page all referencing ADAL you’re going to have issues. The post “Call the MSGraphAPI using OAuth from your web part” gives you an extension that will help isolate ADAL so that you can utilize it as part of a more strongly developed widget pattern. Since my demo is just that, and since my solution will be the only one running on the page that uses the ADAL library I’m not going to address those modifications here. But, I encourage you do so if that is part of your use case.

The ADAL library for JavaScript


Finally, we get to the part where we talk about writing some code. ADAL stands for “Active Directory Authentication Library”. Based on the client you’re using and which authentication endpoint you’re using, there are a multitude of different examples and SDK’s available as you can see on the MSGraphAPI, Getting Started page. Because we’re going to write client side code (aka JavaScript, either transpiled from Typescript or native) and access via Implicit Flow to the MSGraphAPI, we’ll use the adal.js library. It comes in two parts, adal.js and adal-angular.js. If you’re going to use the AngularJS framework, you’ll want both pieces. If not, you can just include adal.js, but there will be more work to do to authenticate and get a token. You can find the source in the ADAL GitHub repo.

User Authentication

One of the things that bothered me was the idea that the user would have to “log in” manually every time the ADAL library would need to authenticate them. In my mind, I envisioned a pop-up that would prompt them for credentials. In the scenario where you’re running this code on your on-premises server in a hybrid scenario, and haven’t set up federated sign-in to your O365 tenant that would be valid, however, in the most likely scenarios I can envision the code would be running in your SharePoint site in your O365 tenant… therefore asking the user to log in again would be annoying at best. Well, sure enough that’s not what happens, the library uses a hidden iframe on the page to make the call to get the user authenticated, since they are technically already authenticated to O365 this is just a matter of “confirming” it for lack of a better term. So, the page does flicker but otherwise this is unnoticeable to the user.

*Note: Thanks to Wictor Wilen for bringing up the issue with using adal.js in IE with a trusted site. Please check out this issue, from the GitHub repo.

ADAL Config

A big part of utilizing the adal.js libraries is to get all the configuration settings correct. I want to highlight some of the configuration properties that I reviewed and what was useful. You’ll see how to put it together and pass it to adal.init() later. The definitions here come straight from the documentation in the adal.js file itself.

  • tenant: string – Your target tenant.
  • clientID: string – Client ID assigned to your app by Azure Active Directory.
  • endpoints: array – Collection of {Endpoint-ResourceId} used for automatically attaching tokens in webApi calls.
  • popUp: boolean – Set this to true to enable login in a popup window instead of a full redirect.Defaults to false.
  • cacheLocation: string – Sets browser storage to either ‘localStorage’ or sessionStorage’. Defaults to ‘sessionStorage’.
  • anonymousEndpoints: array – Array of keywords or URI’s. ADAL will not attach a token to outgoing requests that have these keywords or uri. Defaults to ‘null’.

Using ADAL.js with No Framework

The most tedious coding scenario with ADAL is utilizing it without the AngularJS add-on. I found this blog article on how to do it, but unfortunately for me although it worked initially, when it came time to renew the token the ADAL library was throwing errors. After quite a bit of time on it, reviewing the adal-angular.js file and various other blog posts, I managed to work out a scenario that seems to work reliably.

For simplicity’s sake, I’m showing an entire html file including the JavaScript in one code snippet. I commented the code extensively but in a nutshell, we’ll do the following:

  • 1. For simplicity code is executed on page load using jQuery’s document.ready function. The goal of that bit of code is to determine if AAD is doing a callback and if so, let the adal.js library handle it.
    • a. If not a callback, check if the user is authenticated, if not, call the ADAL login function
    • b. If not a callback, and user is authenticated, then execute any initialization code we want to run.
  • 2. When a call needs to be made against the MSGraphAPI, e.g., the sympraxis.getGraphData function, first get the token by calling the sympraxis.getAuthToken function (which returns a promise since it may need to make an asynchronous call to AAD, and if so we need to wait until that completes.
    • a. If the token is in the cache, return it by resolving he promise.
    • b. If the token is not in the cache, acquire a new one and then resolve the promise with the new token.
  • 3. Make the REST call to the MSGraphAPI and include the token in the header.

Using Angular 1.x framework with ngRoute

If you’re a fan of the AngularJS framework, then the adal-angular.js library does all the heavy lifting for you. It extends both AngularJS’s $http provider and the ngRoute directive. It adds the bearer token that was retrieved using the adal.js library to the $httpProvider in your REST calls for you. In addition, it accepts an additional configuration setting on each of your routes which determines whether AD login should be required or not. If set to true, when you navigate to the particular route, the adal-angular.js library makes sure the user is logged in, and then also makes sure the $httpProvider appends the token. If it’s not set – or set to false – then the token will not be appended to the $http calls. Also, note here that I’ve utilized html5Mode on the $locationProvider. I did that because of a recommendation in the documentation that indicated that having it on fixes issues with endless callbacks. I too found this to be an issue, but only when bypassing ngRoute. For safety, I put it in both examples, but I’ll leave it to you to test whether it’s necessary in your solution or not.

So, at this point I’m sure you can see that this scenario is significantly simplified from our “No Framework” version above. Other than the changes to the .config, no other changes are necessary. You just go about your business making $http calls and the adal-angular.js library does the rest .

Angular 1.5+ using Components

Angular version 1.5 introduced a new concept called “Components” which was viewed widely as a superior architectural strategy for building Angular applications. So much so a very similar schema was adopted for Angular 2. With components, you generally do not use ngRoute. Further, with many widget solutions, routing is overkill. So, we need to consider another strategy for managing when the $http provider should include the token and, because ngRoute was making sure the user is authenticated for us (as I noted in the previous section), we’re going to need to handle that as well.

For authentication, we’ll reuse the concepts we discussed in the “No Framework” section by making sure on page load we trap the callback and allow the ADAL.js library to handle it. Because this is a component there is the handy $onInit() function. That will work perfectly for our needs.

Now to handle server calls that are not meant to have the token amended… enter, anonymousEndpoints. In this scenario, our configuration would not include the $routeProvider. Instead we would include relative URLs we want to ignore when making $http calls. In this case I included two anonymous endpoints, one for the location of my component templates, and the other is the SharePoint REST APIs.

I specified relative URLs in the anonymousEndpoints array we want to ignore because if you review the code that decides if the $http call should append the bearer token to it, you can see that if the URL includes http or https it will try to find a matching endpoint. If it does not find one, it will utilize the token that was used for the login resource. For example, if you try to make a call against the SharePoint REST API and the URL you use includes https://mytenant.sharepoint.com it’s going to append the bearer token and subsequently fail. Also, note that I only included the root of the URLs I want ADAL to ignore. That is because the test for anonymous endpoint uses a “contains” check.

The controller for the component we create would then define an $onInit() function that would handle login for those components that need it. There are certainly other ways architecturally to handle this, but I wanted to keep things simple so I wouldn’t lose the point in the elegance of the architecture. At a baseline this is what it would look like. We’re going to expand on this, and explain the SP_EP url in the _CONFIG in Part 3.

Summary

Now we’ve completed Part 2, you should have everything you need to go off and start making calls to the MSGraphAPI. But, if you’re interested, Part 3 will bring all of this together and show you how to create an Excel spreadsheet from scratch, add it to a SharePoint document library, and then manipulate it with the Excel API’s. Please stay tuned…

Resources

OAuth Flows

Andrew Connell – Looking at the Different OAuth2 Flows Supported in AzureAD for Office 365 APIs
Microsoft – Integrating applications with Azure Active Directory
Matt Velloso – Troubleshooting common Azure Active Directory Errors
Microsoft – Should I use the v2.0 endpoint?

ADAL

GitHub – Azure Active Directory Library for JS
Cloud Identity – Introducing ADAL JS v1
Cloud Identity – ADAL JavaScript and AngularJS – Deep Dive
Cloud Identity – Getting Acquainted with AuthenticationResult
Cloud Identity – Getting Acquainted with ADAL’s Token Cache
Microsoft – Call the Microsoft Graph API using OAuth from your web part

Microsoft Graph API

Microsoft – Microsoft Graph permission scopes
Microsoft – App authentication with Microsoft Graph

Series Navigation<< Extending SharePoint with ADAL and the Microsoft Graph API – Part 1 (The Setup)Extending SharePoint with ADAL and the Microsoft Graph API – Part 3 (The Execution) >>

Published by

Julie Turner, MVP

Julie has been building software on primarily the Microsoft platform for over 20 years. With a degree in Electrical Engineering specializing in microprocessor system design from Worcester Polytechnic Institute she came at software initially from a very low level but quickly realized a love and aptitude for developing rich user experiences and solutions. She worked her way up through internal IT ranks reaching a Director of IT position before realizing more impact could be made in consulting and really focused in on the SharePoint platform in 2007. Since then her focus has been on the SharePoint platform, Office 365, Azure, and client side development. She's the co-author of the Widget Wrangler JavaScript library and continues to try and help innovate SharePoint and Office 365 solutions for her clients. She is a 2017 recipient of the Microsoft MVP award for Office Servers and Services.

5 thoughts on “Extending SharePoint with ADAL and the Microsoft Graph API – Part 2 (The Authorization)”

  1. One thing to bear in mind is that ADAL.js does not work properly with Internet Explorer and SharePoint Online, if SharePoint Online is in your trusted zone – which you normally have for SSO to work.

    1. After going back and forth with Wictor on a private Slack I think I finally get the Internet Explorer zones issue. Basically, every site that uses ADAL,js has to be in the same zone as login.microsoftonline.com. This is a problem for SharePoint users because tenantname.sharepoint.com and tenantname-my.sharepoint.com are often in the Local Intranet or Trusted Sites zone. So, if you want to access the Graph API from a SharePoint web part you need to put login.microsoftonline.com in the same zone as the sharepoint.com URLs. Now, what if you also use abc.azurewebsites.net and xyz.azurewebsites.net which both use ADAL.js? You’re going to have to put those sites in the same zone as login.microsoftonline.com too or they won’t work properly. As time goes on and more and more sites use ADAL.js you end up having a huge list of sites in whatever zone login.microsoftonline.com is in.

Leave a Reply