2

This question builds on How to get Microsoft Graph API Access token from Node Script?, however, as a first-time user of, I don't have the required reputation for commenting on the accepted answer in that thread.

The thing is, I tried to implement the approach suggested by the accepted answer, but somewhere it goes wrong. The below code is part of an async function, and I can already tell you that the ONEDRIVE_TENANT_URI is of the format XXX.onmicrosoft.com.

const endpoint = `https://login.microsoftonline.com/${process.env.ONEDRIVE_TENTANT_URI}/oauth2/token`;
const requestParams = {
  grant_type: "client_credentials",
  client_id: process.env.ONEDRIVE_APP_ID,
  client_secret: process.env.ONEDRIVE_CLIENT_SECRET,
  resource: "https://graph.windows.net"
};

const authResponse = await request.post({
  url: endpoint,
  form: requestParams
});

authResponse gets, as its body, just a string with the requestParams as defined above filled out.

If I submit the post request via Postman, with the same parameters as x-www-form-urlencoded, I DO get an access_token in the response body.

So... What do I do wrong? Maybe - but I don't think so - it's because this function is invoked by a (for testing purposes) POSTMAN GET request with a json-formatted body?

Tony Ju
  • 14,891
  • 3
  • 17
  • 31
Fronzie
  • 33
  • 6
  • 3
    There isn't a lot to go on here. Please edit your question and add some additional code, specifically where you're setting `requestParams`. It also isn't clear how or where you registered your application. – Marc LaFleur Mar 14 '19 at 18:08
  • Added some code as per your request! – Fronzie Mar 15 '19 at 09:25

2 Answers2

1

You can download the sample here. And fill in the credentials in config.js. You can find them from Azure portal. enter image description here

This is the code to get access token.

auth.getAccessToken = function () {
  var deferred = Q.defer();

  // These are the parameters necessary for the OAuth 2.0 Client Credentials Grant Flow.
  // For more information, see Service to Service Calls Using Client Credentials (https://msdn.microsoft.com/library/azure/dn645543.aspx).
  var requestParams = {
    grant_type: 'client_credentials',
    client_id: config.clientId,
    client_secret: config.clientSecret,
    resource: 'https://graph.microsoft.com'
  };

  // Make a request to the token issuing endpoint.
  request.post({ url: config.tokenEndpoint, form: requestParams }, function (err, response, body) {
    var parsedBody = JSON.parse(body);
    console.log(parsedBody);
    if (err) {
      deferred.reject(err);
    } else if (parsedBody.error) {
      deferred.reject(parsedBody.error_description);
    } else {
      // If successful, return the access token.
      deferred.resolve(parsedBody.access_token);
    }
  });

  return deferred.promise;
};

You will get the access token successfully. enter image description here

Tony Ju
  • 14,891
  • 3
  • 17
  • 31
  • Yeah, I know it should work - but it doesn't. I follow the same example/tutorial, and it does work in Postman as a direct POST request, but it seems to fail when it's part of a larger stream of functions initiated by a GET request... although I don't think that should present a problem... I also changed graph.windows.net to graph.microsoft.com, to no avail. – Fronzie Mar 15 '19 at 09:27
  • Did you make any change of the sample? – Tony Ju Mar 15 '19 at 09:31
  • There is no error message, it just returns a useless response with a lot of data, but not the data that you expect. As mentioned, it has a 'body', but its value is just the query string of the requestParams – Fronzie Mar 15 '19 at 09:39
  • Please modify your request code to these code to have a try. request.post({ url: config.tokenEndpoint, form: requestParams }, function (err, response, body) { var parsedBody = JSON.parse(body); console.log(parsedBody); if (err) { deferred.reject(err); } else if (parsedBody.error) { deferred.reject(parsedBody.error_description); } else { // If successful, return the access token. deferred.resolve(parsedBody.access_token); } }); – Tony Ju Mar 15 '19 at 09:46
  • request.post({ url: endpoint, form: requestParams },function(err,response,body){ console.log(body); } ) Try this one and see if it works. – Tony Ju Mar 15 '19 at 09:57
  • That works! Why? Is there an issue with the request module in combination with await? Does it not support ES6 fat arrow functionality? – Fronzie Mar 15 '19 at 10:49
  • @Fronzie Just like Marc said, request doesn't natively support promises. And you can find more details here. https://github.com/request/request#promises--asyncawait – Tony Ju Mar 18 '19 at 07:43
0

You've got two issues going on.

The first isn't an issue yet, but it will be once you try to call Microsoft Graph. The resource should be graph.microsoft.net, not graph.windows.net. The graph.windows.net refers to the legacy Azure AD Graph API, not Microsoft Graph.

The other issue, which is the root cause of this error, is await request.post. Request doesn't natively support promises. From the Request the documentation:

request supports both streaming and callback interfaces natively. If you'd like request to return a Promise instead, you can use an alternative interface wrapper for request. These wrappers can be useful if you prefer to work with Promises, or if you'd like to use async/await in ES2017.

Several alternative interfaces are provided by the request team, including:

Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63