41

I'm testing out the Uber API on Postman, and I'm able to send a request with form data successfully. When I try to translate this request using Node.js and the axios library I get an error.

Here is what my Postman request looks like:

Postman POST request

The response I get is: { "error": "invalid_client" }

Here is what I'm doing in Node.js and axios:

var axios = require("axios");

const config = { headers: { 'Content-Type': 'multipart/form-data' } };

axios.post('https://login.uber.com/oauth/v2/token', {
  client_id: '***',
  client_secret: '***',
  grant_type: 'authorization_code',
  redirect_uri: 'http://localhost:8080/',
  code: '***'
}, config)
  .then(function(response) {
    console.log(response.data)
  })
  .catch(function(error) {
    console.log(error)
  })

When I do this, I get a 400 response.

I added the 'multipart/form-data' header because I filled out the form-data in the Postman request. Without the header I get the same result.

I'm expecting to get the same response I'm getting from Postman, is there something wrong with my config variable in the Node.js script?

Any help would be appreciated!

Mike
  • 2,633
  • 6
  • 31
  • 41
  • It seems you are sending an additional parameter in your API call.. When you send additional parameters you are tend to receive this `Invalid Client` error. – David R Jan 20 '17 at 12:58
  • 1
    Have you tried passing the data using `querystring.stringify`? Like this: `var querystring = require('querystring'); axios.post('http://something.com/', querystring.stringify({ foo: 'bar' });` – King Julien Jan 20 '17 at 13:08
  • @KingJulien wrapping the data in the querystring module didn't help me out this time... – Mike Jan 20 '17 at 17:48
  • @KingJulien This `querystring.stringify` worked for me. I was sending data in dict format rather than string – Volatil3 Dec 28 '21 at 11:55

7 Answers7

47

You might be able to use Content-Type: 'application/x-www-form-urlencoded'. I ran into a similar issue with https://login.microsoftonline.com where it was unable to handle incoming application/json.

var axios = require("axios");

axios({
  url: 'https://login.uber.com/oauth/v2/token',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  data: `client_id=${encodeURIComponent('**')}&client_secret=${encodeURIComponent('**')}&grant_type=authorization_code&redirect_uri=${encodeURIComponent('http://localhost:8080/')}&code=${encodeURIComponent('**')}`
})
.then(function(response) {
  console.log(response.data)
})
.catch(function(error) {
  console.log(error)
})

You could also use a function to handle the translation to formUrlEncoded like so

const formUrlEncoded = x =>
   Object.keys(x).reduce((p, c) => p + `&${c}=${encodeURIComponent(x[c])}`, '')

var axios = require("axios");

axios({
  url: 'https://login.uber.com/oauth/v2/token',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  data: formUrlEncoded({
     client_id: '***',
     client_secret: '***',
     grant_type: 'authorization_code',
     redirect_uri: 'http://localhost:8080/',
     code: '***' 
  })
})
.then(function(response) {
  console.log(response.data)
})
.catch(function(error) {
  console.log(error)
})
Reid Evans
  • 1,611
  • 15
  • 19
  • 'qs' npm package mentioned on [another question](https://stackoverflow.com/a/60458100/358006) can do the url encoding. – Peter L Mar 28 '20 at 00:27
  • 1
    this is an outdated answer. these days `axios` [supports sending `multipart/form-data`](https://stackoverflow.com/a/71958251) from Node.js by using one of the polyfills of `FormData` – Boris Verkhovskiy Apr 21 '22 at 17:07
17

Starting with Axios 1.3, you can send multipart/form-data data using FormData:

const axios = require('axios');

const form = new FormData();
form.append('my_field', 'my value');
form.append('my_other_field', 'my second value');

axios.post('http://example.com', form)

FormData is available on Node 17.6.0 (or newer), on older versions you'll have to use a polyfill such as form-data.

If you're using older versions of both Node and Axios, you have to set the Content-Type header yourself as well:

const axios = require('axios');
const FormData = require('form-data');
const form = new FormData();
axios.post('http://example.com', form, { headers: form.getHeaders() })
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
  • `form-data` [is a dependency](https://github.com/axios/axios/blob/v1.x/package.json) of Axios, so you should already have it installed. – Boris Verkhovskiy Dec 31 '22 at 23:54
8

To send data with Content-Type application/x-www-form-urlencoded, wrap your {} with new URLSearchParams(). Like this snippet:

const axios = require("axios");
axios
  .post("https://api.zipwhip.com/user/login", new URLSearchParams({
  username: "hello",
  password: "byby",
}))
  .then((res) => console.log(res.data));


Meir
  • 516
  • 4
  • 19
7

As for 10 June 2017, axios library does not support posting form data in Node.js. Here is the issue on GitHub - https://github.com/mzabriskie/axios/issues/789

We had the similar problem and decided to switch to request library.

anuveyatsu
  • 125
  • 1
  • 7
  • Is this still the issue because I can't post form data by setting `data` parameter, works fine with `request` – Volatil3 Dec 28 '21 at 11:47
  • Yes, I think the issue wasn't fixed and they have closed the issue with the following comment: https://github.com/axios/axios/issues/789#issuecomment-568146899 – anuveyatsu Dec 30 '21 at 05:16
  • 1
    the comment they closed the issue with describes how to do this (by posting a `FormData` object from the `form-data` package) not that they decided they won't fix it. – Boris Verkhovskiy Apr 21 '22 at 17:04
3

This use case is now clearly documented with multiple solutions in the axios docs: https://axios-http.com/docs/urlencoded#form-data

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Henrik Hansson
  • 869
  • 6
  • 6
0

From the error it seems your client_id or client_secret is incorrect. Enable debugging and share the raw request/response (after filtering credentials out).

Dustin Whittle
  • 1,242
  • 7
  • 11
-4

It is not true! You can post data with axios using nodejs. I have done it. The problem is, if you use PHP on the server side, there is a pitfall you need to be aware of. Axios posts data in JSON format (Content-Type: application/json) PHP's standard $_POST array is not populated when this content type is used. So it will always be empty. In order to get post parameters sent via a json request, you need to use file_get_contents("http://php://input") .

A simple PHP script on the server side would be:

if($_SERVER['REQUEST_METHOD']==='POST' && empty($_POST)) {
 $_POST = json_decode(file_get_contents('http://php://input'));
}

Using this method you can avoid the formData dependency. You CAN post data directly from node.js.

salihcenap
  • 1,927
  • 22
  • 25
  • What if posting form data is the only option you have. That is if you don't have access to the API? Please see @Reid Evans answer – Delali Nov 05 '19 at 12:24