Twitter API authorization fails CORS preflight in browser
Asked Answered
T

5

37

I'm trying to do the 3-legged authorization necessary to call the Twitter APIs in a browser. The process starts with getting a request token by POSTing a signed request to /oauth/request_token (this is also how sign in with Twitter begins).

My problem is that before the browser will POST to the Twitter API endpoint, it wants to preflight the request with an OPTIONS method. This preflight request is always returning status 400 (Bad Request).

Here's an example that you can cut and paste into a browser console that supports the Fetch API:

fetch('https://api.twitter.com/oauth/request_token', { method: 'POST', mode: 'cors', headers: new Headers({ authorization: 'xxx' }), body: 'oauth_callback=http%3A%2F%2Flocalhost%2F' });

On Chrome, the preflight request looks like this (Firefox is similar):

OPTIONS /oauth/request_token HTTP/1.1
accept:*/*
accept-encoding:gzip, deflate, sdch
accept-language:en-US,en;q=0.8
access-control-request-headers:authorization, content-type
access-control-request-method:POST
cache-control:no-cache
origin:null
pragma:no-cache
user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36

And the preflight response looks like this:

HTTP/1.1 400 Bad Request
content-length: 0
date: Tue, 08 Mar 2016 22:21:37 GMT
server: tsa_a
x-connection-hash: 529e3d8338caeb980077637d86db5df1

Note that problem is not that I didn't specify a real authorization header in the example above. The value of the authorization header is not used in the preflight request.

If I print out the components of my POST request to the console and assemble the pieces into a curl command (which doesn't preflight) then I can get a request token. But if I try to simulate the preflight request in curl, I haven't been able to get that to work:

$ curl -v -X OPTIONS -H "access-control-request-headers:authorization,content-type" -H "access-control-request-method:POST" -H "origin:http://example.com" https://api.twitter.com/oauth/request_token
*   Trying 199.59.148.20...
* Connected to api.twitter.com (199.59.148.20) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /opt/local/share/curl/curl-ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
*    subject: C=US; ST=CA; L=San Francisco; O=Twitter, Inc.; OU=Twitter Security; CN=api.twitter.com
*    start date: Aug 11 00:00:00 2015 GMT
*    expire date: Aug 15 12:00:00 2016 GMT
*    subjectAltName: api.twitter.com matched
*    issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 High Assurance Server CA
*    SSL certificate verify ok.
> OPTIONS /oauth/request_token HTTP/1.1
> Host: api.twitter.com
> User-Agent: curl/7.47.1
> Accept: */*
> access-control-request-headers:authorization,content-type
> access-control-request-method:POST
> origin:http://example.com
> 
< HTTP/1.1 400 Bad Request
< content-length: 0
< date: Tue, 08 Mar 2016 23:06:44 GMT
< server: tsa_a
< x-connection-hash: 66174829ef6d3f5e5ec641ac080ad19c
< 
* Connection #0 to host api.twitter.com left intact

What am I missing that will let me do a successful CORS preflight to https://api.twitter.com/oauth/request_token?

Thymol answered 8/3, 2016 at 23:14 Comment(0)
T
63

So the unsatisfying resolution appears to be that the Twitter API does not support CORS. This seems a little astonishing to me, as it means that the API cannot be used from a browser.

That policy decision is probably related to their OAuth implementation, which is vulnerable to anyone with access to the calling platform. Maybe that was okay back in 2010, but most of the other major internet players have figured out how to do client-based authorization.

Thymol answered 9/3, 2016 at 17:50 Comment(25)
Oh wow, I'm reading this a year later for a toy app and still doesn't seem to be resolved. Thanks for detailing this here!Hogan
Same issue still in 2018.Dropsy
still here in 2019Subglacial
its 2019 end and still :(Shopping
its 2020 and its still hereReligieuse
You should vote to add this feature via this proposition twitterdevfeedback.uservoice.com/forums/930250-twitter-api/…Jillane
its 2021 and its still here :(Condyle
its March of 2021 and its still here:)Yezd
2022 and its still hereStratigraphy
I haven't time traveled yet but its july 2021 and its still here!Mahler
I'm Jonas from 2052 and it's still here, the real reason for my travel was to build a Twitter login for my SPA.Armitage
End of 2021 and still the same issue :(Moue
Its 2022 and still no support :( wasted lot of time and then just found this post.Choler
It's 2022 and it's still here.Dromedary
2023.. Same thingStarry
June 29, 2022 and still the same thing, I hope they fix this soon.Allare
it's Aug 2022 and it;s still here :(Oubre
October 2022 checking in, whats good guys.Welloiled
nothing's changed... :(Unhook
2022 about to end, issue still existsMycenaean
2023 and it's still hereStradivari
Sean H in with the FIRST! :D 1/4/2023 and still here...Tarrel
End of June 2023 and it's still hereAugmentation
2024 and its still here. is there any other alternatives to use the API for my Angular project, please let me knowRyan
@HemanthGirimath Did you found some solution?Lachish
M
2

I recently faced this issue. I didn't want to spend lots of time creating node server, so I used Netlify's serverless functions. It is super easy and straight forward + free

I followed this blog, it worked perfectly fine for me: https://www.digitalocean.com/community/tutorials/nodejs-solve-cors-once-and-for-all-netlify-dev

Moue answered 2/12, 2021 at 10:33 Comment(0)
C
0

A workaround and it is a long way around is to build a proxy server that you run with node or something else, I've done this a few times now, this is a good starter repo for someone running into this issue. It has the downside of being React specific, but you could always rip out the react ui and just setup with whatever you need: hcra twitter build.

Its forked from a Create React App/Node Express boilerplate by Mars Hall

You will need to clone it and run git fetch and then checkout twitter-req branch.

Cleodel answered 18/6, 2018 at 14:3 Comment(0)
H
0

One workaround would be to create a NodeJS server for the same and call the Node API requesting Twitter API from front-end.

Homogeneous answered 18/6, 2018 at 14:8 Comment(1)
If you want to use the Twitter streaming API, then you would also have to set up a Web Socket server, push all the tweets on to the socket. Then you have to build a WS client in your front end. It's a big workaround.Gilstrap
G
0

Check this workaround: https://stackoverflow.com/a/43881141

If you don’t control the server your frontend JavaScript code is sending a request to, and the problem with the response from that server is just the lack of the necessary Access-Control-Allow-Origin header, you can still get things to work—by making the request through a CORS proxy.

In short, prefix the request so the full URI looks something like this:

https://cors-anywhere.herokuapp.com/https://api.twitter.com/oauth/request_token

Unfortunately, you will not be able to use most Twitter libraries this way, but you can continue using fetch with the cors-anywhere prefix.

Edit: The mentioned cors-anywhere web service is no longer permanently available, but instead can be temporarily "activated" for development use.

Grieco answered 23/7, 2019 at 17:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.