Search code examples
typescriptsharepointazure-active-directoryaccess-tokenspfx

Intermittently Can't Get AAD Token


I've created a custom web part for SharePoint Online that connects to a web API secured by AAD and then displays the results to the screen. It works well but several times throughout the day it stalls while trying to retrieve the access token. It doesn't throw an exception, it just hangs.

At first, my code reflected what was in the docs for connecting to AAD secured resources in SharePoint but when the AadHttpClient started hanging, I read about other people having issues with it. So, I changed my code to create an AadTokenProvider and call getToken() on it to generate a token I could manually add to the header on a regular httpClient.get() request.

This didn't solve the issue but it did tell me that the getToken() is definitely where it stops. I'm not sure if getTokenProvider() is returning something funky that is causing getToken() to hang or if getToken() is hanging for reasons related to SharePoint or AAD.

It seems to fail most often after a period of inactivity too, like it's attempting to get a stale provider/token and failing to renew but I don't know how to confirm this or what to do about it.

Why am I having trouble getting a token reliably?

Here's my code:

this.context.aadTokenProviderFactory.getTokenProvider()
  .then((provider) => { 
      return provider.getToken('<Client ID for my API>', false); //THIS IS WHERE IT HANGS    
  })
  .then((token) => { 
    this.context.httpClient
      .get('https://www.example.com/api/myAPI/', AadHttpClient.configurations.v1, {
        headers: [
          ['accept', 'application/json'],
          ['Authorization', 'Bearer ' + token]
        ]
      })
      .then((res: HttpClientResponse): Promise<any> => {
        return res.json();
      })
      .then(data => {
          //process data
      }, (err: any): void => {
        this.context.statusRenderer.renderError(this.domElement, err);
      });
    })
  .catch((err) => {
    this.context.statusRenderer.renderError(this.domElement, "Failed to retrieve data.");
  });

EDIT: I noticed that when it doesn't work, I get several of the following error in the console:

Blocked script execution in '<URL>' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.

The '<URL>' is something like https://my tenant.sharepoint.com/_forms/spfxsinglesignon.aspx


Solution

  • Microsoft Bug

    After some back and forth with Microsoft, we confirmed this to be a bug related to the underlying token acquisition code. Apparently there's a race() condition in the authentication code that isn't resolving properly.

    As of now (January 2020), there is no fix in place but per the bug report, there should be something ready in about a month.

    Workaround

    We discovered that the issue occurs when your custom web part is on the same page as other OOTB web parts, like the Document Library and Events web parts. By moving the Document Library web part to a different page, the issue went away.

    So for anyone bumping into this issue, you should be able to get around the problem by separating 1 or more of the OOTB web parts from your custom web part. At least until the bug has been fixed.