Search code examples
javascriptnode.jsoauth-2.0xmlhttprequest

Can't properly send Request Body on the node.js version of XMLHttpRequest when doing POST request


I'm trying to make a PSOT request to the Microsoft Oauth2.0 token URL using NodeJS and the XMLHttpRequest library found here. However, I am having the problem, that I just can't send a proper Request body alongside with the Request. I have already tried using FormData from here, I tried URLSearchParams, and I tried making it a String in the way we know it from our Adress bar in GET Requests. Below you can see my Code from when I tried doing it in a GET URL form, and in the part that I made a commend, you can see my attempts of using FormData instead.

var xhr = new XMLHttpRequest();
        xhr.open("POST", 'https://login.microsoftonline.com/common/oauth2/v2.0/token');

        /*var data = new FormData();
        //var data = new URLSearchParams();
        data.append('client_id', clientId);
        data.append("grant_type", "authorization_code");
        data.append("scope", "openid email profile");
        data.append("code", code);
        data.append("redirect_uri", "http://" + req.headers.host + req.url);
        data.append("client_secret", secret);
        Error message on this one: TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received an instance of FormData
Same message with URLSearchParams, except it received an instance of URLSearchParams
*/

        var data = 'client_id=' + clientId;
        data += '&grant_type=authorization_code';
        data += '&scope=openid%20email%20profile';
        data += '&code=' + code;
        data += '&redirect_uri=' + encodeURIComponent("http://" + req.headers.host + req.url);
        data += '&client_secret=' + secret;
        //This one gives me an error message from Microsoft: {"error":"invalid_request","error_description":"AADSTS900144: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID: ratherNotSay\r\nCorrelation ID: ratherNotSay\r\nTimestamp: 2020-02-10 10:37:36Z","error_codes":[900144],"timestamp":"2020-02-10 10:37:36Z","trace_id":"ratherNotSay","correlation_id":"ratherNotSay","error_uri":"https://login.microsoftonline.com/error?code=900144"}
//This must mean that the request body can not have been submitted in the right way.

        xhr.onreadystatechange = () => {
          if (xhr.readyState == 4) {
            console.log(xhr.status + "\n" + xhr.responseText + "\n");
          }
        };
        xhr.send(data);

Solution

  • You can transform a URLSearchParams instance into a query string, like the one that you build manually, by using the toString() method.

    I don't know if the Content-Type header is set to application/x-www-form-urlencoded by default in the node-XMLHTTPRequest version, but it couldn't hurt to set it manually.

    const xhr = new XMLHttpRequest();
    xhr.open("POST", 'https://login.microsoftonline.com/common/oauth2/v2.0/token');
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    
    const data = new URLSearchParams();
    data.append('client_id', clientId);
    data.append("grant_type", "authorization_code");
    data.append("scope", "openid email profile");
    data.append("code", code);
    data.append("redirect_uri", "http://" + req.headers.host + req.url);
    data.append("client_secret", secret);
    
    xhr.onreadystatechange = () => {
        if (xhr.readyState == 4) {
            console.log(xhr.status + "\n" + xhr.responseText + "\n");
        }
    };
    
    xhr.send(data.toString());