Search code examples
javascriptoutlookoffice365office-app

Testing javascript web app - 401 (Unauthorized) error


I have been trying to understand the example given in this link:

I have created the office app for outlook along the same lines to access the office 365 Outlook APIs The link.

I have created the app using Napa Dev Tools.

The errors I am getting are

  1. XMLHttpRequest cannot load https://outlook.office365.com/api/v1.0/me/messages. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:8080' is therefore not allowed access. The response had HTTP status code 401. - I get this error when CORS is not allowed.

  2. GET https://outlook.office365.com/api/v1.0/me/messages 401 (Unauthorized) - I get this error when I enable CORS.

How would I make the use of Outlook REST API calls and test the application locally?

Any help regarding this is much appreciated! Thanks!

Edit: Code with the comment "//changed" was modified to make the example work-

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>O365 CORS Sample</title>
<style>
body {
    font-family:'Segoe UI';
}

.paddedElement {
    margin-top: 5px;
}

.hidden {
visibility: hidden;
}
</style>
</head>
<body>
<h2>O365 CORS Sample</h2>
<label for="TxtOauthToken">OAuth Token:</label>
<input type="text" id="TxtOauthToken" size="80" />
<br />
<label for="endpointUrl">Endpoint URL:</label>
<input type="text" id="endpoint" size="80" />
<br />
<input type="button" class="paddedElement" id="getToken" value="Get Token">
<input type="button" class="paddedElement" id="doCors" value="Make CORS Request" visibility="hidden" />
<br />
<br />
<label for="results" class="hidden paddedElement" id="resultHeading">Results:</label>
<br />
<label id="debugMessage"></label>
<pre id="results"></pre>
<script type="text/javascript">
(function (window) {
 var isCorsCompatible = function() {
 try
 {
 var xhr = new XMLHttpRequest();
 xhr.open("GET", getEndpointUrl());
 xhr.setRequestHeader("authorization", "Bearer " + token);
 xhr.setRequestHeader("accept", "application/json");
 xhr.onload = function () {
 // CORS is working.
 console.log("Browser is CORS compatible.");
 }
 xhr.send();
 }
 catch (e)
 {
 if (e.number == -2147024891)
 {
 console.log("Internet Explorer users must use Internet Explorer 11 with MS15-032: Cumulative security update for Internet Explorer (KB3038314) installed for this sample to work.");
 }
 else
 {
     console.log("An unexpected error occurred. Please refresh the page.");
 }

 }
 };

 var urlParameterExtraction = new (function () {
         function splitQueryString(queryStringFormattedString) {
         console.log("Query: " + queryStringFormattedString);
         var split = queryStringFormattedString.split('&');

         // If there are no parameters in URL, do nothing.
         if (split == "") {
         return {};
         }

         var results = {};

         // If there are parameters in URL, extract key/value pairs.
         for (var i = 0; i < split.length; ++i) {
         var p = split[i].split('=', 2);
         if (p.length == 1)
         results[p[0]] = "";
         else
         results[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
         }

         return results;
         }

         // Split the query string (after removing preceding '#').
         this.queryStringParameters = splitQueryString(window.location.hash.substr(1));
 })();

 var token = urlParameterExtraction.queryStringParameters['access_token'];

 if (token == undefined) {
     document.getElementById("TxtOauthToken").value = "Click \"Get Token\" to trigger sign-in after entering the endpoint you want to use.";

     document.getElementById("doCors").style.visibility = "hidden";
 }
 else {
     document.getElementById("TxtOauthToken").value = token;
     document.getElementById("doCors").style.visibility = "visible";
     document.getElementById("getToken").style.display = "none";
 }

 // Constructs the authentication URL and directs the user to it.
 function requestToken() {
     // Change clientId and replyUrl to reflect your app's values
     // found on the Configure tab in the Azure Management Portal.
     var clientId    = 'd18f9842-eec8-4d81-93e4-24ced3d59199';   //Changed
     var replyUrl    = 'https://localhost:8080/echo';  //Changed
         var resource    = "https://graph.windows.net/"; //Changed

     var authServer  = 'https://login.windows.net/common/oauth2/authorize?';
         //var endpointUrl = getEndpointUrl();
         var endpointUrl = 'http://outlook.office365.com/api/v1.0/me/messages';  //Changed

     var responseType = 'token';

     var url = authServer +
         "response_type=" + encodeURI(responseType) + "&" +
         "client_id=" + encodeURI(clientId) + "&" +
         "resource=" + encodeURI(resource) + "&" +
         "redirect_uri=" + encodeURI(replyUrl);

     window.location = url;
 }

 document.getElementById("getToken").onclick = requestToken;

 function getEndpointUrl() {
     return document.getElementById("endpoint").value;
 }

 function getFilesFromO365() {
     document.getElementById("results").textContent = "";

     // Check browser compatbility. Check console output for details.
     isCorsCompatible();

     try
     {
         var xhr = new XMLHttpRequest();
         xhr.open("GET", getEndpointUrl());

         // The APIs require an OAuth access token in the Authorization header, formatted like this: 'Authorization: Bearer <token>'.
         xhr.setRequestHeader("Authorization", "Bearer " + token);

         // Process the response from the API.
         xhr.onload = function () {
             document.getElementById("resultHeading").style.visibility = "visible";

             if (xhr.status == 200) {
                 var formattedResponse = JSON.stringify(JSON.parse(xhr.response), undefined, 2);
                 document.getElementById("results").textContent = formattedResponse;
             } else {
                 document.getElementById("results").textContent = "HTTP " + xhr.status + "<br>" + xhr.response;
             }
         }

         // Make request.
         xhr.send();
     }
     catch (err)
     {
         document.getElementById("resultHeading").style.visibility = "visible";
         document.getElementById("results").textContent = "Exception: " + err.message;
     }
 }

 document.getElementById("doCors").onclick = getFilesFromO365;

})(window);
</script>
</body>

</html>

Solution

  • The example you're trying to follow is not for an Add-in, but for a JavaScript web app that uses the Office 365 APIs. I believe it's possible to have an Add-in that uses the Office 365 APIs, but that's not what the example you're following is doing.

    In any case, the 401 you are getting can be fixed by setting the right permissions for your app in Azure AD. The example you're following is using the Files API so it sets the Read user's files permission in step 10 in the Register your app with Azure AD section. For your case, you'll need to add the Office 365 Exchange Online application and then select the correct permissions.

    Additionally, I noticed you changed the resource variable to https://graph.windows.net/, which is incorrect for the Mail API anyway. You'll need to set that to https://outlook.office365.com.