Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Axios breaking changes in simple requests beginning with 0.21.2 and up coming from v0.21.1 #4129

Closed
JaielZeus opened this issue Oct 3, 2021 · 17 comments

Comments

@JaielZeus
Copy link

JaielZeus commented Oct 3, 2021

Describe the issue

Using Axios to refresh Twitch Token suddenly breaks when updating from v0.21.1 to 0.21.2 and newer.

Example Code

It works jsut fine in v0.21.1 but breaks in higher versions. An example usage is down below.

The main issue here is that I get the emssage that the "client_id" is missing by twitch API, although as you can see it is included in the options object. Something must have changed in v0.21.2 and higher for this to happen somehow suddenly

const Axios = include('axios');

options= {
  method: 'post',
  baseURL: 'https://id.twitch.tv/oauth2/',
  url: 'token',
  params: {
    grant_type: 'refresh_token',
    refresh_token: '---------',
    client_id: '---------',
    client_secret: '---------'
  },
  headers: {},
  data: {}
}

Axios(options)

Expected behavior, if applicable

It should work and send everything provided including the client_id of course as in the example above

Environment

  • Axios Version 0.21.2
  • Adapter HTTP
  • Node.js Version 8.x
  • OS: Win 10

Additional context/Screenshots

Pls help me updating to v0.22.0 by somehow pointing me in the right direction to solve this, thanks

@TheVaan
Copy link

TheVaan commented Oct 4, 2021

Who tells you, that client_id is missing? Can you post your error message?

@JaielZeus
Copy link
Author

You seem to be sceptic, but I guess it would help to show all data. I am gonna post the error now and some excerts of the whole request and response object then.

Error: Request failed with status code 400

The config object in the error message:

  config: {
    url: 'token',
    method: 'post',
    data: '{}',
    headers: {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/json',
      'User-Agent': 'axios/0.21.2',
      'Content-Length': 2
    },
    params: {
      grant_type: 'refresh_token',
      refresh_token: '-redacted-',
      client_id: '-redacted-',
      client_secret: '-redacted-'
    },
    baseURL: 'https://id.twitch.tv/oauth2/',
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    validateStatus: [Function: validateStatus],
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    }
  },

The request object with parts omitted:

  request: ClientRequest {
    _events: [Object: null prototype] {
      ...
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    socket: TLSSocket {
      ...
      _hadError: false,
      _parent: null,
      _host: 'id.twitch.tv',
      ...
    },
    connection: TLSSocket {
      ...,
      _hadError: false,
      _parent: null,
      _host: 'id.twitch.tv',
      ...
    },
    _header: 'POST /oauth2/token?grant_type=refresh_token&refresh_token=-redacted-&client_id=-redacted-&client_secret=-redacted- HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: application/json\r\n' +
      'User-Agent: axios/0.21.2\r\n' +
      'Content-Length: 2\r\n' +
      'Host: id.twitch.tv\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _onPendingData: [Function: noopPendingOutput],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      maxCachedSessions: 100,
      _sessionCache: [Object]
    },
    socketPath: undefined,
    method: 'POST',
    path: '/oauth2/token?grant_type=refresh_token&refresh_token=-redacted-&client_id=-redacted-&client_secret=-redacted-',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      readable: false,
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      socket: [TLSSocket],
      connection: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 400,
      statusMessage: 'Bad Request',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular],
      responseUrl: 'https://id.twitch.tv/oauth2/token?grant_type=refresh_token&refresh_token=-redacted-&client_id=-redacted-&client_secret=-redacted-',
      redirects: []
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    _redirectable: Writable {
      _writableState: [WritableState],
      writable: true,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 2,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function],
      _currentRequest: [Circular],
      _currentUrl: 'https://id.twitch.tv/oauth2/token?grant_type=refresh_token&refresh_token=-redacted-&client_id=-redacted-&client_secret=-redacted-'
    },
    ...
  },

The response object:

  response: {
    status: 400,
    statusText: 'Bad Request',
    headers: {
      date: 'Mon, 04 Oct 2021 13:01:07 GMT',
      'content-type': 'application/json',
      'content-length': '45',
      connection: 'close',
      server: 'nginx/1.18.0',
      'access-control-allow-origin': '*',
      'x-ctxlog-logid': '1-615afb13-1226ae5213a6b7357bb862cc'
    },
    config: {
      url: 'token',
      method: 'post',
      data: '{}',
      headers: [Object],
      params: [Object],
      baseURL: 'https://id.twitch.tv/oauth2/',
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      adapter: [Function: httpAdapter],
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      validateStatus: [Function: validateStatus],
      transitional: [Object]
    },
    request: -see above-
    },
    data: { status: 400, message: 'missing client id' }
  },

@JaielZeus
Copy link
Author

The usual request I do only works on 0.21.1. I changed to 0.21.2 now jsut to get the errors again. So there has been some change in 0.21.1 -> 0.21.2 that broke my code somehow. And my code is pretty lame and standard, I do no funky stuff other than what oyu would find in the docs about how to make a request with axios. I dont know what causes this!

@bastika
Copy link

bastika commented Oct 5, 2021

I can confirm this. We have the same problem with axios post requests where the data parameter is passed as a string. It worked fine with strings, but since the recent update to 0.21.2 this does not work anymore. We fixed this by passing data as an object.

const exampleObject = { 'key': value }

Old call:
await axios.post(url,JSON.stringify(exampleObject), options);

New call:
await axios.post(url, exampleObject, options);

@DigitalBrainJS
Copy link
Collaborator

@bastika That was fixed in v0.21.4, although it doesn't make much sense to use JSON.stringify manually.

@cruizba
Copy link

cruizba commented Oct 6, 2021

We're having the same problem. This is how our Json was sent in version 0.21.1

{"customSessionId":"silky-coffee-ape","mediaMode":"ROUTED","recordingMode":"MANUAL","forcedVideoCodec":"VP8","allowTranscoding":false,"defaultRecordingProperties":{"name":"","hasAudio":true,"hasVideo":true,"outputMode":"COMPOSED","recordingLayout":"BEST_FIT","resolution":"1280x720","frameRate":25,"shmSize":536870912}}

And this in 0.21.2

"{\"customSessionId\":\"silky-coffee-ape\",\"mediaMode\":\"ROUTED\",\"recordingMode\":\"MANUAL\",\"defaultRecordingProperties\":{\"name\":\"\",\"hasAudio\":true,\"hasVideo\":true,\"outputMode\":\"COMPOSED\",\"recordingLayout\":\"BEST_FIT\",\"resolution\":\"1280x720\",\"frameRate\":25,\"shmSize\":536870912}}"

This breaks somehow with some clients. It looks like a breaking change somehow.

@cruizba
Copy link

cruizba commented Oct 6, 2021

Seems like version 0.21.4 solves the problem, as @DigitalBrainJS said for @bastika error :). I don't know if the main reason of the issue it's solved with this version

@jasonsaayman
Copy link
Member

Please use 0.21.4 as that solves the problem :)

@JaielZeus
Copy link
Author

JaielZeus commented Oct 6, 2021

Hi, thank you for the input all. But I feel I should have been clearer in my word choice.

I did state

v0.21.2 and higher
and
It works jsut fine in v0.21.1 but breaks in higher versions.

So I really meant in higher versions and not jsut in v0.21.2.

I tested first udpating to v0.22.0 and saw it broke, then I backtracked every version trying v0.21.4, v0.21.3 and v0.21.2 and therefore I could conclude that there was some major change done in v0.21.2 that my code breaks. In v0.21.1 the code works perfectly fine like it should, jsut to make it clear.

An example was already given how I do it and yeah this is all I can say for now. I wanna request to open this issue again @jasonsaayman please and hope that it can be looked into again.

I am gonna take a look at comparing the changes amde from v0.21.1 -> v0.21.2 over the weekend when I have more time but I hope I can get some extra eyes to help with that and fix that issue with Axios.

Thank you!

@jasonsaayman jasonsaayman reopened this Oct 6, 2021
@davidmcl
Copy link

I have the problem described by JaielSoft as well; 0.21.1 works fine, anything above 0.21.1 breaks the calls.

environment: nodejs 16.12; amazon linux 2

Doing a Postman GET to an api endpoint that adds a couple headers (Authorization & Accept) and then
targets the Recurly V3 api https://developers.recurly.com/api/v2019-10-10/

I use the... let response = await axios(apiConfig); ... format and get a 400 Bad Request, in what appears to be a circular error in 0.21.2 - confirmed same behavior also in 0.21.4 & 0.23.0 (didn't bother to check 0.22.x)

return to 0.21.1 with no app code change, and all works as expected

LONG log attached from the response - with sensitive info replaced by ***removed***

Hope this helps.

David

axios 21.2 error log.txt

@chinesedfan
Copy link
Collaborator

chinesedfan commented Oct 27, 2021

The most possible buggy commit may be #3688, which changes the default transformRequest. And looks like 'Content-Type': 'application/json' is set by @JaielSoft in #4129 (comment), which matches the problem of @cruizba in #4129 (comment).

-    if (utils.isObject(data)) {
+    if (utils.isObject(data) || (headers && headers['Content-Type'] === 'application/json')) {
       setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
       return JSON.stringify(data);
     }

And I have a very simple template to debug the config related issues. Please try and compare the adapter printed config between different axios versions.

var adapter = function(config) {
  console.log(config)
  return Promise.resolve({data: 12})
}

// set the log adapter
axios({ adapter, ... })

@robbporto
Copy link

This is still happening if you try to make a POST request without sending any body params.

@Behinder
Copy link

Behinder commented Dec 19, 2021

I haven't changed anything in my code and starting from today axios request to last.fm API gives me

Incorrect protocol version (missing clientID/version/username)

what the hell? apparently problem was created by using headers

 "Content-Type": "application/json"

instead of "Accept": "application/json"

@JaielZeus
Copy link
Author

Any updates on this issue?

@mmilano
Copy link

mmilano commented Jun 7, 2022

am having a problem (the same problem?)
with every version over 0.21.1 too…0.21.1 works, anything more recent does not.

the xhr request itself is functioning fine; data is returning as indicated in the browser network console.
but the call never completes, and remains hung in time.

@jasonsaayman
Copy link
Member

Hi 👋

Please could you retry with the latest version and open a new issue should this error still be relevant?

Thanks

@JaielZeus
Copy link
Author

JaielZeus commented Nov 3, 2022

@jasonsaayman It still persists as of the newest release v1.1.3

Something happened between 0.21.1 and 0.21.2 which made axios unusable for me.

I guess sticking to 0.21.1 is the only way to go for me for now...

EDIT: there is something with how the body/data is bein used differently. I am adding an empty body/data object to the request and I think in 0.21.1 an empty body was being sent as undefined maybe but in 0.21.2 it jsut literally sent an empty object.

I tested it by putting the client_id as a body parameter like so:

{
   client_id: 'xxxxx'
}

It worked like that somehow. The fault might lie in the service I am sending it to but thats the "bug" that made my code unsable unfortunately with >= v0.21.2

Here an example of a not working and a working code:

Works only in v0.21.1:

      const params = {
        grant_type: 'refresh_token',
        refresh_token: TwitchHelper.auth.refreshToken,
        client_secret: TwitchHelper.auth.clientSecret,
        client_id: TwitchHelper.auth.clientId,
      };
      // parameters are: method, baseUrl, url, params, headers, data.
      const options = WebHelper.getOptions('post', 'https://id.twitch.tv/oauth2/', 'token', params, {}, {});

This change works now in >= v0.21.2, tested in v1.1.3:

      const data = {
        grant_type: 'refresh_token',
        refresh_token: TwitchHelper.auth.refreshToken,
        client_secret: TwitchHelper.auth.clientSecret,
        client_id: TwitchHelper.auth.clientId,
      };
      // parameters are: method, baseUrl, url, params, headers, data
      const options = WebHelper.getOptions('post', 'https://id.twitch.tv/oauth2/', 'token', {}, {}, data );

My explanation/take on it is: Twitch's api seems to take a higher priority when there is a body sent with the request over the parameters, even an empty object {}. In v0.21.1 an empty object in the body was converted to undefined. Starting with v0.21.2 the empty object got literally sent as an empty object {} and thus twitch api was looking at the body of the request and found only emptiness and ignored the url parameters.

I moved therefore my credentials for the api endpoint into the body/data of the request and got the problem resolved now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests