🙌

サーバーレスでプロダクト開発したらOAuthで詰まった話【React+node.js+Express+TwitterOAuth】

2021/10/23に公開

まとめ

  • GAEで3レッグ認証OAuthを試した。(API)
  • TwitterのOAuthフローは結構歴史が古く、自分は数年前の記事ばかりあって不安になってしまったが、結果的に数年更新がされていないライブラリを使うことになった。きちんと動いているので、凄い心配する必要はないよ、という応援記事。
  • DBを使いたくなかったため画像の受け渡しをbase64変換し保存するというhackになってしまったが、基本はDBで保存した方が良いと感じた。

本文

構成図

Frontend:

deploy:Netlify(githubのmasterが更新されると自動デプロイ)

  • React
    多言語対応でDOMを動的に変化させる必要があり、勉強がてら採用。
  • Typescript
    一度もTypescriptを触ったことがないなと気が付き、型もわかり辛くなってきたためリファクタしつつ部分的に導入。
  • i18next
    多言語対応にあたり、stateで言語セットを保持することが無茶な設計だと感じ導入。
  • konva
    inputに入力された内容をcanvasに動的に反映させたかったため採用。
  • material-ui
    CSS設計で悩む時間を極力減らしたく、今回はデザインに強いこだわりがなかったため採用。

BackendAPI

deploy:Google App Engine(nodejs)
元々GCPを使った経験があり支払い情報もあらかじめ入っていて導入コストが小さいと見て採用。

  • express
  • express-session
    APIのルーティングのために採用。
  • node-twitter-api
    認証に使用。passportと悩んだがpassport-twitterという補助ライブラリを使うためにpassportのバージョンを下げる必要があり、バージョン管理が面倒だと思い一つのライブラリで完結するnode-twitter-apiを採用した。
  • buffer
    base64をデコードするために導入。
  • twitter
    OAuth後のmedia/uploadやツイートに使用。

やったこと

Front

  • フロントでkonva(canvasのライブラリ)を使用しcanvasを生成
  • 生成したものをbase64に変換
  • APIにPOST

API

  • APIで受け取ってsessionとして保存

  • OAuth

  • sessionで保存していたbase64を画像にデコード

  • Twitterのmedia/uploadに投稿しツイートさせる

ひっかかりポイント

OAuthについて何も知らなかった

TwitterのOAuthフローはOAuth1.0aを使用しているのだが、そもそもOAuthにバージョンがあると知らなかった。それぞれめちゃくちゃに調べてOAuth1.0と2.0を混同してしまった。

公式ドキュメントのどれを見ればいいかがわからなくなった

「結局どれを使えば自分のやりたいことは実現できるのか?」という部分でつまづきがあった。基本的にツイートや画像付きツイートをする場合は3レッグ認証OAuthフローというものに則れば良い。下記のリンクを見ながらnode-twitter-apiに沿って実装すれば問題なく実装できる。
https://developer.twitter.com/ja/docs/authentication/oauth-1-0a/obtaining-user-access-tokens

なぜかセッションが切れる

開発の際FrontendではPOST先がlocalhostになっていたがcallbackURLでは127.0.0.1に指定していたため、localhostと127.0.0.1が別とみなされセッションが切れていた。きちんと両方とも同じドメインになっているかを確認すること。

結局TwitterでやるOAuthフローって何やってるの?

凄くざっくり言うとaccess tokenとAccess token secretを引っ張ってくるフローのこと。下記にやっていることを書く

事前準備

TwitterDevelopersで以下三つを設定する。keyとsecretは自動で発行され、callbackは自分でURL指定する。

  • oauth_consumer_key(=API Key):次に使う
  • oauth_consumer_secret(=API Key Secret)
  • oauth_callback:callback処理の時にこれ以外のURLはエラーになる

1. oauth/request_tokenにPOSTする

oauth_consumer_keyとoauth_callbackを投げると以下の三つが手に入る

  • oauth_token
  • oauth_token_secret
  • oauth_callback_confirmed

2. https://api.twitter.com/oauth/authorize にGETする

パラメータとしてoauth_tokenを付けるとログイン画面に飛ぶ。ログインに成功すると1で設定したcallbackURLに飛ぶ。callbackURLは事前準備と1がきちんと合致していること。
CallbackURLで指定したところに飛ばされ、パラメータとして以下二つが手に入る

  • oauth_token
  • oauth_verifier
    このoauth_tokenは1のoauth_tokenと一致していること。一致していないとなりすましの可能性がある。

3. oauth/access_tokenにPOSTする

CallbackURLで指定したところに飛ばされるので、そこで以下三つを投げる

  • oauth_consumer_key:事前準備で手に入れた奴
  • oauth_token:2(=1)で手に入れた奴
  • oauth_verifier:2で手に入れた奴
    すると以下が返ってくる
  • oauth_token
  • oauth_token_secret
    この二つは1と同じように見えるが、実はaccess tokenとAccess token secretのことである。
    これを保存してtwitterのclientライブラリで用いる。

これらのフローを簡単にしてくれるのがOAuthライブラリであり、passportであったりnode-twitter-apiであったりする。

Discussion