Roland Oldengarm - Independent IT Contractor

Living in the coolest little capital Wellington, New Zealand!

Angular ADAL JS + SharePoint REST API in non-root site collections

I’ve been struggling with the following. I’m building a SPA Office Add-in, which communicates with Office 365, using the (awesome) ADAL JS libraries. My app queries the SharePoint Search and downloads files.

As a starting point, I’ve been using this example: https://github.com/OfficeDev/O365-WebApp-MultiTenant

To access the REST API endpoints I was using Angular $http, so I don’t have to worry about adding access tokens to the requests. It was all working fine, until I wanted to access files in non-root site collections. I saw a HTTP/401 in Fiddler, but the access token was attached, so that seemed weird. The response was:

{“error”:”invalid_client”,”error_description”:”Invalid audience Uri ‘{azure_app_id’.”}

… where azure_app_id is my Azure Application ID.

When I would retrieve the access token manually via authService.acquireToken(resource) and set it in the Authorization header, it would work (resource = the URL to SharePoint).

After some Googling and asking around, nobody could really help me. So I attached the debugger to the Angular ADAL JS libraries. I started debugging in the $http request interceptor, and found that at line 272

var resource =authService.getResourceForEndpoint(config.url);

resource would equal the Azure Application ID, but it should be the URL to my tenant. For e.g. search queries in the root site collection it was the URL to my tenant and that is working.

So, diving into getResourceForEndpoint I noticed that it did not find a URL for my non-rootsite URL and defaulted to the loginResource.

I first tried to set the loginResource in the config, but that did not work (too much to describe here). The solution is to add the URL as an endpoint:

// $scope.rootSiteServiceEndpointUri = the tenant root site URL, e.g. https://tenant.sharepoint.com, returned by the Discovery Service
adalAuthenticationService.config.endpoints[contextInfoUrl] = $scope.rootSiteServiceEndpointUri;

And then everything magically worked!
I’m not sure if I have done something wrong elsewhere, it seems odd that I need to add every site as an endpoint. It works, but not entirely happy with the workaround.

3 Comments

  1. Thanks for the post! It gives me hope, but I’m struggling to recreate your solution… you wouldn’t be able to share more of the code that you used? Thanks!

    • rolandoldengarm

      August 9, 2016 at 3:20 pm

      Sorry, I don’t have access to the original source code anymore.
      I recall that I just added that line to where I configure my adalAuthenticationService, e.g. in your config or run method for your module definition.

      • Yep, that’s where I was putting it… ah well… in the end I just side-stepped the whole issue by hosting the SPA on a page in SharePoint (stripped of all but the basics to get a page to run). No good for a multi-tenant solution obviously, but that wasn’t an issue for my use-case.

Leave a Reply

Your email address will not be published.

*