436

I have some parameters that I want to POST form-encoded to my server:

{
    'userName': '[email protected]',
    'password': 'Password!',
    'grant_type': 'password'
}

I'm sending my request (currently without parameters) like this

var obj = {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  },
};
fetch('https://example.com/login', obj)
  .then(function(res) {
    // Do stuff with result
  }); 

How can I include the form-encoded parameters in the request?

0

19 Answers 19

574

Even simpler:

fetch('https://example.com/login', {
    method: 'POST',
    body: new URLSearchParams({
        'userName': '[email protected]',
        'password': 'Password!',
        'grant_type': 'password'
    })
});

Docs: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch

Sign up to request clarification or add additional context in comments.

6 Comments

This won't automagically add the header 'Content-Type': 'application/x-www-form-urlencoded, right?
@lasseschou Not sure it's necessary: fetch docs say that body could be an URLSearchParams
you can also pass a formdata object, so when using a HTML form, thats shorter new URLSearchParams(formData)
Image
how can this be done without a library
@B''HBi'ezras--BoruchHashem, no library, everything is built-in
|
520

You have to put together the x-www-form-urlencoded payload yourself, like this:

var details = {
    'userName': '[email protected]',
    'password': 'Password!',
    'grant_type': 'password'
};

var formBody = [];
for (var property in details) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(details[property]);
  formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

fetch('https://example.com/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
  },
  body: formBody
})

Note that if you were using fetch in a (sufficiently modern) browser, instead of React Native, you could instead create a URLSearchParams object and use that as the body, since the Fetch Standard states that if the body is a URLSearchParams object then it should be serialised as application/x-www-form-urlencoded. However, you can't do this in React Native because React Native does not implement URLSearchParams.

5 Comments

The ES6 way : const formBody = Object.keys(details).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(details[key])).join('&');
This polyfill for URLSearchParams github.com/WebReflection/url-search-params may work for React Native or older browsers.
Another similar way: const formBody = Object.entries(details).map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value)).join('&')
It converts the json array parameter to string
I have tried all of the suggested methods. No matter what I do, fetch injects unwanted quotes around the body, directly into the string - opening and closing quotes. This causes the params to be parsed, e.g. like this: '"mykey': 'myvalue"'. Which makes calling APIs impossible, as these of course just result in 400 errors (server recognizes mykey, not "mykey). Anybody else have this issue? Baffling.
87

Use URLSearchParams

https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

var data = new URLSearchParams();
data.append('userName', '[email protected]');
data.append('password', 'Password');
data.append('grant_type', 'password');

2 Comments

It is part of React Native now. Be sure to call toString() on the data before passing it request body.
Even after RN said that they implemented URLSearchParams, I'm still having issues. I don't think it's implemented in accordance with the spec and it isn't just a drop in solution. Please consider reading URLSearchParams 'Error: not implemented' if you try to drop in URLSearchParams and still have issues.
41

Just did this and UrlSearchParams did the trick Here is my code if it helps someone

import 'url-search-params-polyfill';
const userLogsInOptions = (username, password) => {



// const formData = new FormData();
  const formData = new URLSearchParams();
  formData.append('grant_type', 'password');
  formData.append('client_id', 'XXXX-app');
  formData.append('username', username);
  formData.append('password', password);
  return (
    {
      method: 'POST',
      headers: {
        // "Content-Type": "application/json; charset=utf-8",
        "Content-Type": "application/x-www-form-urlencoded",
    },
      body: formData.toString(),
    json: true,
  }
  );
};


const getUserUnlockToken = async (username, password) => {
  const userLoginUri = `${scheme}://${host}/auth/realms/${realm}/protocol/openid-connect/token`;
  const response = await fetch(
    userLoginUri,
    userLogsInOptions(username, password),
  );
  const responseJson = await response.json();
  console.log('acces_token ', responseJson.access_token);
  if (responseJson.error) {
    console.error('error ', responseJson.error);
  }
  console.log('json ', responseJson);
  return responseJson.access_token;
};

3 Comments

the return from userLogsInOptions has json:true
Image
without a library is the best way
remember to replace '+' with %20
27

You can use UrlSearchParams and then do a toString() like so:

Here is a simple way of doing it:

fetch('https://example.com/login', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    body: new URLSearchParams({
        'userName': '[email protected]',
        'password': 'Password!',
        'grant_type': 'password'
    })
    .toString()
})
.then(res => {
    //Deal with response:
})

1 Comment

I sent the response res to the console. Instead of showing the server response, it shows "[object Response]". Also, can you please use 'await'?
24

No need to use jQuery, querystring or manually assemble the payload. URLSearchParams is a way to go and here is one of the most concise answers with the full request example:

fetch('https://example.com/login', {
  method: 'POST',
  body: new URLSearchParams({
    param: 'Some value',
    anotherParam: 'Another value'
  })
})
  .then(response => {
    // Do stuff with the response
  });

The same technique using async / await.

const login = async () => {
  const response = await fetch('https://example.com/login', {
    method: 'POST',
    body: new URLSearchParams({
      param: 'Some value',
      anotherParam: 'Another value'
    })
  })

  // Do stuff with the response
}

Yes, you can use Axios or any other HTTP client library instead of native fetch.

Comments

11
var details = {
    'userName': '[email protected]',
    'password': 'Password!',
    'grant_type': 'password'
};

var formBody = [];
for (var property in details) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(details[property]);
  formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

fetch('http://identity.azurewebsites.net' + '/token', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: formBody
})

it is so helpful for me and works without any error

refrence : https://gist.github.com/milon87/f391e54e64e32e1626235d4dc4d16dc8

Comments

11

You can use FormData and URLSearchParams to post as application/x-www-form-urlencoded with the example below:

If you have a form:

<form>
    <input name="username" type="text" />
    <input name="password" type="password" />
    <button type="submit">login</button>
</form>

You can add use the JS below to submit the form.

const form = document.querySelector("form");

form.addEventListener("submit", async () => {
    const formData = new FormData(form);
    try {
        await fetch("https://example.com/login", {
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            },
            body: new URLSearchParams(formData),
        });
    } catch (err) {
        console.log(err);
    }
});

1 Comment

FYI you don't need to set the content-type header. See this answer
8
*/ import this statement */
import qs from 'querystring'

fetch("*your url*", {
            method: 'POST',
            headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
            body: qs.stringify({ 
                username: "akshita",
                password: "123456",
            })
    }).then((response) => response.json())
      .then((responseData) => {
         alert(JSON.stringify(responseData))
    })

After using npm i querystring --save it's work fine.

Comments

4

Just Use

import  qs from "qs";
 let data = {
        'profileId': this.props.screenProps[0],
        'accountId': this.props.screenProps[1],
        'accessToken': this.props.screenProps[2],
        'itemId': this.itemId
    };
    return axios.post(METHOD_WALL_GET, qs.stringify(data))

Comments

4

If you are using JQuery, this works too..

fetch(url, {
      method: 'POST', 
      body: $.param(data),
      headers:{
        'Content-Type': 'application/x-www-form-urlencoded'
      }
})

1 Comment

With $.param({value: function(){return 'values'; }}) it is possible to pass functions as parameters.
3

According to the spec, using encodeURIComponent won't give you a conforming query string. It states:

  1. Control names and values are escaped. Space characters are replaced by +, and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by %HH, a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., %0D%0A).
  2. The control names/values are listed in the order they appear in the document. The name is separated from the value by = and name/value pairs are separated from each other by &.

The problem is, encodeURIComponent encodes spaces to be %20, not +.

The form-body should be coded using a variation of the encodeURIComponent methods shown in the other answers.

const formUrlEncode = str => {
  return str.replace(/[^\d\w]/g, char => {
    return char === " " 
      ? "+" 
      : encodeURIComponent(char);
  })
}

const data = {foo: "bar߃©˙∑  baz", boom: "pow"};

const dataPairs = Object.keys(data).map( key => {
  const val = data[key];
  return (formUrlEncode(key) + "=" + formUrlEncode(val));
}).join("&");

// dataPairs is "foo=bar%C3%9F%C6%92%C2%A9%CB%99%E2%88%91++baz&boom=pow"

Comments

3

Just set the body as the following

var reqBody = "username="+username+"&password="+password+"&grant_type=password";

then

fetch('url', {
      method: 'POST',
      headers: {
          //'Authorization': 'Bearer token',
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      },
      body: reqBody
  }).then((response) => response.json())
      .then((responseData) => {
          console.log(JSON.stringify(responseData));
      }).catch(err=>{console.log(err)})

Comments

2

You can use react-native-easy-app that is easier to send http request and formulate interception request.

import { XHttp } from 'react-native-easy-app';

* Synchronous request
const params = {name:'rufeng',age:20}
const response = await XHttp().url(url).param(params).formEncoded().execute('GET');
const {success, json, message, status} = response;


* Asynchronous requests
XHttp().url(url).param(params).formEncoded().get((success, json, message, status)=>{
    if (success){
       this.setState({content: JSON.stringify(json)});
    } else {
       showToast(msg);
    }
});

Comments

1

In the original example you have a transformRequest function which converts an object to Form Encoded data.

In the revised example you have replaced that with JSON.stringify which converts an object to JSON.

In both cases you have 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' so you are claiming to be sending Form Encoded data in both cases.

Use your Form Encoding function instead of JSON.stringify.


Re update:

In your first fetch example, you set the body to be the JSON value.

Now you have created a Form Encoded version, but instead of setting the body to be that value, you have created a new object and set the Form Encoded data as a property of that object.

Don't create that extra object. Just assign your value to body.

1 Comment

Hi @Quentin. I've just radically slimmed down the question in order to try and make it into a more useful reference for future readers; in doing so, I've entirely invalidated your answer which refers to the details and bugs of the asker's original code. I suppose you have the right to revert my edit if you want to - in theory, we're not meant to make answer-invalidating edits, which is what I've done - but if you'd be willing to, I think it'd be better to just delete this answer instead; IMO the question is much nicer without the Angular code or previous failed attempt.
1

wrapped fetch in a simple function

async function post_www_url_encdoded(url, data) {
    const body = new URLSearchParams();
    for (let key in data) {
        body.append(key, data[key]);
    }
    return await fetch(url, { method: "POST", body });
}

const response = await post_www_url_encdoded("https://example.com/login", {
    "name":"ali",
    "password": "1234"});
if (response.ok){ console.log("posted!"); }

Comments

0

Here is the code I used to convert FormData into "application/x-www-form-urlencoded" type

const formData = new FormData(form);
const urlSearchParams = new URLSearchParams();

formData.forEach((value, key) => {
  urlSearchParams.append(key, value);
});

fetch('/form', {
    method: 'POST',
    body: urlSearchParams,
})

Comments

-1

Posting this in case it helps anyone:

I've been working on the integration with an OAuth2.0 server provided by one of our partners. The vendor's API documentation asks to provide the "Content-Type: application/x-www-form-urlencoded" header on each request. However, while attempting to send a POST request to get the access token, the server kept responding with an HTTP 400 "Invalid request" error. After several tries, I realized that the vendor's OAUTh server seems to be expecting the value of the "redirect_uri" to be unencoded. Therefore, as a workaround, I had to manually encode each value of the payload and leave the "redirect_uri" unencoded.

Here's an example of the code for your reference:

const getAccessToken = () => {
    let payloadEncoded = '';
    payloadEncoded += 'client_id=' + <OAUTH CLIENT ID>
    payloadEncoded += '&client_secret=' + <OAUTH SECRET>
    payloadEncoded += '&grant_type=authorization_code';
    payloadEncoded += '&code=' + <OAUTH CODE>
    payloadEncoded += '&redirect_uri=https://<REDIRECT URI UNENCODED>';

    const options = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        },
        body: payloadEncoded
    };

    fetch('https://<OAUTH SERVER HOST>/c2id/token', options)
        .then(response => response.json())
        .then(data => {console.log(data);
        .catch(error => console.error(error));
}

Obviously, I will reach out to the vendor to make the correction on their side.

I hope this helps!

1 Comment

The values are vulnerable to injection, need use escape secuences.
-72
+50

For uploading Form-Encoded POST requests, I recommend using the FormData object.

Example code:

var params = {
    userName: '[email protected]',
    password: 'Password!',
    grant_type: 'password'
};

var formData = new FormData();

for (var k in params) {
    formData.append(k, params[k]);
}

var request = {
    method: 'POST',
    headers: headers,
    body: formData
};

fetch(url, request);

8 Comments

This is not application/x-www-form-urlencoded, but multipart/form-data
I concur, this request won't have "application/x-www-form-urlencoded" as Content-Type but "multipart/form-data".
What different would it make when it comes to the server actually finding the credentials sent? Is the OAuth end point designed to accept one content type and reject others?
@Mzn - For example if you're using a service like Google's Closure Compiler API, the server will only accept application/x-www-form-urlencoded, not multipart/form-data.
You'll have to do extra processing on the server, when submitting FormData objects. Basically process a regular form as if it were a file upload. What is the advantage of FormData objects for regular forms?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.