Question

I want Access token in sharepoint Hosted addin in order to consume Microsoft Graph Api. When I hit Access Token Api (https://login.microsoftonline.com/dimensiondata2.onmicrosoft.com/oauth2/token) using Postman I am able to get access token, But using code, I am getting 401 unauthorized error. I refer this Documentation

Following is the error:-[ { "SchemaVersion":"15.0.0.0","LibraryVersion":"16.0.8412.1210","ErrorInfo":null,"TraceCorrelationId":"7e4eb29e-c011-0000-1892-c2fb5c7aa49d" },2,{ "_ObjectType_":"SP.WebResponseInfo","Body":"The remote server returned the following error while establishing a connection - 'Unauthorized'.","Headers":null,"StatusCode":401 } ]

This is How i created Request object:-

var context = SP.ClientContext.get_current();
        var request = new SP.WebRequestInfo();
         var body = "client_id=" + client_id + "&client_secret=" + client_secret + "&resource=" + resource + "&grant_type=" + grant;
        request.set_url(
            "https://login.microsoftonline.com/companyname.onmicrosoft.com/oauth2/token"
        );

        // We need the response formatted as JSON.
    request.set_headers({"Content-Type": "application/x-www-form-urlencoded" });

        request.set_method("POST");
        request.set_body(body);
        var response = SP.WebProxy.invoke(context, request);

In my AppManifest.xml I have added following EndPoint:-

<RemoteEndpoints>
<RemoteEndpoint Url="https://login.microsoftonline.com/domainname.onmicrosoft.com/oauth2/token" />
</RemoteEndpoints>
Was it helpful?

Solution

Disclaimer
In general, from a security perspective, it's a bad idea to store a client secret in javascript (browser), like in SharePoint hosted app scenario. Make sure you understand what you're doing.

Below code works for me (I've modified OOB one generated by VS when you select SharePoint add-in):

'use strict';

ExecuteOrDelayUntilScriptLoaded(initializePage, "sp.js");

function initializePage()
{
    var context = SP.ClientContext.get_current();
    var user = context.get_web().get_currentUser();
    var request = new SP.WebRequestInfo();
    var response;
    // This code runs when the DOM is ready and creates a context object which is needed to use the SharePoint object model
    $(document).ready(function () {
        getUserName();
    });

    // This function prepares, loads, and then executes a SharePoint query to get the current users information
    function getUserName() {
        context.load(user);

        var body = "client_id=" + client_id + "&client_secret=" + encodeURIComponent(client_secret) + "&resource=" + "https://graph.microsoft.com" + "&grant_type=" + "client_credentials";
        request.set_url(
            "https://login.microsoftonline.com/company.onmicrosoft.com/oauth2/token"
        );

        // We need the response formatted as JSON.
        request.set_headers({"Content-Type": "application/x-www-form-urlencoded" });

        request.set_method("POST");
        request.set_body(body);
        response = SP.WebProxy.invoke(context, request);

        context.executeQueryAsync(onGetUserNameSuccess, onGetUserNameFail);
    }

    // This function is executed if the above call is successful
    // It replaces the contents of the 'message' element with the user name
    function onGetUserNameSuccess() {
        console.log(response);
        $('#message').text('Hello ' + user.get_title());
    }

    // This function is executed if the above call fails
    function onGetUserNameFail(sender, args) {
        alert('Failed to get user name. Error:' + args.get_message());
    }
}

Please take a note on a few things:
In your AppManifest.xml add below endpoint:

<RemoteEndpoints>
    <RemoteEndpoint Url="https://login.microsoftonline.com" />
</RemoteEndpoints> 

Also, I guess you missed & sign between body parameters, consider my example:

var body = "client_id=" + client_id + "&client_secret=" + encodeURIComponent(client_secret) + "&resource=" + "https://graph.microsoft.com" + "&grant_type=" + "client_credentials";  

And finally, encode client secret, because it might contain special symbols:

encodeURIComponent(client_secret)
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top