Авторизация Twitter API не проходит предварительную проверку CORS в браузере

Я пытаюсь выполнить трехстороннюю авторизацию, необходимую для вызова API Twitter в браузере. Процесс начинается с получения токена запроса путем размещения подписанного запроса в /oauth/request_token (это также, как начинается вход в Twitter).

Моя проблема заключается в том, что перед тем, как браузер отправит POST в конечную точку API Twitter, он хочет предварительно обработать запрос методом OPTIONS. Этот предпечатный запрос всегда возвращает статус 400 (неверный запрос).

Вот пример, который вы можете вырезать и вставить в консоль браузера, которая поддерживает 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' });

В Chrome предварительный запрос выглядит так (Firefox похож):

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

И предполетный ответ выглядит так:

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

Обратите внимание, что проблема не в том, что я не указал настоящий заголовок авторизации в приведенном выше примере. Значение заголовка авторизации не используется в предварительном запросе.

Если я распечатаю компоненты моего запроса POST на консоль и соберу части в команду curl (которая не выполняет предварительную проверку), то я могу получить токен запроса. Но если я попытаюсь смоделировать предварительный запрос в curl, я не смогу заставить это работать:

$ 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

Чего мне не хватает, что позволит мне успешно выполнить предварительную проверку CORS на https://dev.twitter.com/oauth/reference/post/oauth/request_token?

5 ответов

Решение

Таким образом, неудовлетворительное решение заключается в том, что API Twitter не поддерживает CORS. Это кажется мне немного удивительным, так как это означает, что API нельзя использовать из браузера.

Это политическое решение, вероятно, связано с их реализацией OAuth, которая уязвима для всех, кто имеет доступ к вызывающей платформе. Возможно, это было хорошо еще в 2010 году, но большинство других крупных интернет-игроков выяснили, как сделать авторизацию на основе клиента.

Я недавно столкнулся с этой проблемой. Я не хотел тратить много времени на создание сервера узлов, поэтому я использовал бессерверные функции Netlify. Это очень легко и просто + бесплатно.

Я следил за этим блогом, он отлично сработал для меня: https://www.digitalocean.com/community/tutorials/nodejs-solve-cors-once-and-for-all-netlify-dev

Одним из обходных путей может быть создание сервера NodeJS для него и вызов API-интерфейса Node, запрашивающего API-интерфейс Twitter из внешнего интерфейса.

Обходной путь, и это долгий путь, это создать прокси-сервер, который вы запускаете с узлом или чем-то еще, я уже делал это несколько раз, это хорошее начальное репо для кого-то, кто сталкивался с этой проблемой. Недостатком является специфичность React, но вы всегда можете извлечь пользовательский интерфейс реакции и просто настроить все, что вам нужно: hcra twitter build.

Его разветвляют из шаблона приложения для создания приложений React /Node Express от Mars Hall

Вам нужно будет клонировать его и запустить git fetch а затем оформить заказ twitter-req ветка.

Поскольку я не могу комментировать, проверьте этот обходной путь: /questions/9247073/v-zaprashivaemom-resurse-otsutstvuet-zagolovok-access-control-allow-origin-pri-popyitke-poluchit-dannyie-iz-rest-api/9247095#9247095

Короче говоря, префикс запроса, чтобы полный URI выглядел примерно так:

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

К сожалению, вы не сможете использовать большинство библиотек Twitter таким образом, но вы можете продолжать использовать fetch с префиксом cors-where.

Другие вопросы по тегам