1

I am trying to call the Twitter API in a React App and get the following error

Fetch API cannot load https://api.twitter.com/1.1/account/verify_credentials.json. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 400. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I know what Access-Control-Allow-Origin means. I think I followed all the steps per the Twitter API (Authorizing a request, Creating a signature) but maybe I am overlooking something in my code.

Also I did not find anything in the API docs that say I have to use a server to call their API, but maybe I missed something.

Below is the function literal fetchUser that gets the user information.

export const fetchUser = async () => {
  const oauths = {...OAUTHS, oauth_nonce: generateNonce(), oauth_timestamp: Math.floor(Date.now() / 1000)};
  const oauthKeys = Object.keys(oauths);
  const oauthValues = Object.values(oauths);
  const baseUrl = `${ROOT_API_URL}verify_credentials.json`;
  const signature = generateOauthSignature(
    oauths,
    HTTP_GET,
    baseUrl,
    CONSUMER_SECRET,
    OAUTH_SECRET
  );

  const response = await fetch(baseUrl, {
    method: `${HTTP_GET}`,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': `OAuth ${oauthKeys[0]}="${oauthValues[0]}",${oauthKeys[1]}="${oauthValues[1]}",oauth_signature="${signature}",${oauthKeys[2]}="${oauthValues[2]}",${oauthKeys[3]}="${oauthValues[3]}",${oauthKeys[4]}="${oauthValues[4]}",${oauthKeys[5]}="${oauthValues[5]}"`,
    }
  });
  const body = await response.json();

  if (response.status !== 200) 
    throw Error(body.message);

  return body;
}

Take a look at the entire code I am using (CodePen)

VLAZ
  • 26,331
  • 9
  • 49
  • 67
esausilva
  • 1,964
  • 4
  • 26
  • 54
  • i'm pretty sure you need a server, as there's no CORS headers in the docs... there are a variety of 3rd party tools/services that "webify" aspects of the twitter API for use from client-side JS. – dandavis Jul 29 '17 at 20:03
  • Thanks for the info, do you know of a good tool to do that? I did a quick Google search but can't seem to find anything – esausilva Jul 29 '17 at 20:32
  • As far a good tool, can try setting up an instance of https://github.com/Rob--W/cors-anywhere/ or such, and see if you can make that solve the problem in the way you need. For more details see https://stackoverflow.com/questions/20035101/no-access-control-allow-origin-header-is-present-on-the-requested-resource/42744707#42744707 – sideshowbarker Jul 29 '17 at 21:19
  • See https://stackoverflow.com/questions/35879943/twitter-api-authorization-fails-cors-preflight-in-browser/35898961#35898961 and see the statement “the typical pattern is that requests to the Twitter API happen at the backend rather than directly, say, from within a browser-based app” at https://twittercommunity.com/t/will-twitter-api-support-cors-headers-soon/28276/3. I guess most everybody continues to deal with this either by writing custom handling into the server-side code for their web apps, or else by using some library that does it for whatever server-side runtime they’re using – sideshowbarker Jul 29 '17 at 21:21
  • 1
    I’m not sure a generic CORS proxy such as https://github.com/Rob--W/cors-anywhere/will actually help in the case where the browser’s been triggered to do a preflight OPTIONS request—which is what’s happening in the case in the question. The reason a generic CORS proxy may not solve anything in that case is, the OPTIONS request needs to happen without authentication—because the browser does that OPTIONS on its own and doesn’t to send the Authorization header+value from your code when it does it. But the 400 response from Twitter seems to indicate they require authentication for OPTIONS requests – sideshowbarker Jul 29 '17 at 21:29

2 Answers2

0

I had to create a Node server to call the API, no biggie

esausilva
  • 1,964
  • 4
  • 26
  • 54
-1

I do not know wether or not the Twitter API allows CORS, but if it does, specifying cors mode in your request should do the trick

const response = await fetch(baseUrl, {
  method: `${HTTP_GET}`,
  mode: 'cors',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': `OAuth ${oauthKeys[0]}="${oauthValues[0]}",${oauthKeys[1]}="${oauthValues[1]}",oauth_signature="${signature}",${oauthKeys[2]}="${oauthValues[2]}",${oauthKeys[3]}="${oauthValues[3]}",${oauthKeys[4]}="${oauthValues[4]}",${oauthKeys[5]}="${oauthValues[5]}"`,
}

});

Robert Falkén
  • 2,287
  • 2
  • 16
  • 16