简体   繁体   中英

Trying to get Outlook Calendar events with Javascript, receiving a 401 Unauthorized error?

So I've got a custom .aspx page with pure JS/jQuery (so no Angular) that I upload to Sharepoint Online and can add as a webpart or iFrame to a site in Sharepoint Online. I want to display Outlook calendar events and I also use FullCalendar.io for the displaying part.

This also includes ADAL (Azure AD) security because it's needed for Outlook API.

So first I authenticate with Azure AD, get my acquired token and then pass that token to the function that builds my FullCalendar.io calendar on the page. This will try to get the Outlook Calendar events and display them nicely on the FullCalendar.

Here's the examples I followed:
https://codeatwork.wordpress.com/2017/04/16/using-outlook-rest-apis-in-sharepoint-online/
https://github.com/AzureAD/azure-activedirectory-library-for-js
https://www.paitgroup.com/blog/display-events-from-an-outlook-calendar-in-sharepoint-using-office-365-apis

I've also added the permissions from link 1 to my Azure AD registered App in the Azure portal!

Here's my code:

<script>

  var $this = this;

  $(document).ready(function() {
    window.config = {
          tenantId: '{tenant}',
          clientId: '{clientId}',
          popUp: true,
          redirectUri: '{redirectURI}',
          endpoints: {
            "https://outlook.office.com/api/v2.0/me/events":"https://outlook.office.com/",
          }
    };

    var authenticationContext = new AuthenticationContext(config);
    authenticationContext.handleWindowCallback();

    if (authenticationContext.getCachedUser()) {
      authenticationContext.acquireToken(config.clientId, function (errorDesc, token, error) {
        if (error) { //acquire token failure
          if (config.popUp) {
              // If using popup flows
              authenticationContext.acquireTokenPopup(config.clientId, null, null,  function (errorDesc, token, error) {});
          }
          else {
          // In this case the callback passed in the Authentication request constructor will be called.
              authenticationContext.acquireTokenRedirect(config.clientId, null, null);
          }
        }
        else {
          //acquired token successfully
          $this.DisplayEvents(token);
        }
      });
    }
    else {
        // Initiate login
        authenticationContext.login();
    }
  });

  function DisplayEvents(adalToken) {
    $('#calendar').fullCalendar({
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'month,agendaWeek,agendaDay,listWeek'
      },
      navLinks: true, // can click day/week names to navigate views
      editable: true,
      eventLimit: true, // allow "more" link when too many events
      events: function(start, end, timezone, callback) {
        var headers = new Headers();
        var bearerToken = "Bearer " + adalToken;
        headers.append('Authorization', bearerToken);
        var options = {
          method: 'GET',
          headers: headers,
          mode: 'no-cors'
        };
        var outlookEndpoint = 'https://outlook.office.com/api/v2.0/me/events?$select=Subject,Organizer,Start,End';

        fetch(outlookEndpoint, options)
          .then(function (response) {
            console.log(response);
          });
      }
    });
  }

</script>  

As you can see, the token is passed to the "fetch" call in the events function of the fullCalendar() function. I've tried doing a normal ajax 'GET' call, but I get CORS errors. Same when I leave out "mode: 'no-cors'" from my options. Fetch is being done because of the github example I've linked above!

Now I'm receiving a 401 Unauthorized error and response that's filled with status:0 and body: null etc.

Anyone else has had this issue or can see what I'm doing wrong to make the authentication fail?

You need to modify your acquireToken method as below. Just replace "config.clientId" with " https://outlook.office.com/ ".

if (authContext.getCachedUser()) {
        authContext.acquireToken("https://outlook.office.com/", function (error, token) {
            if (error) { //acquire token failure
                if (config.popUp) {
                    // If using popup flows
                    authContext.acquireTokenPopup("https://outlook.office.com/", null, null, function (errorDesc, token, error) { });
                }
                else {
                    // In this case the callback passed in the Authentication request constructor will be called.
                    authContext.acquireTokenRedirect("https://outlook.office.com/", null, null);
                }
            }
            else {
                //acquired token successfully
                // alert('token success');
                DisplayEvents(token);
            }
        });
    }
    else {
        // Initiate login
        authContext.login();
    }

Besides, you can find the 401 error details by using Rest Client or postman. For example, this is the response in Rest Client. 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM