はじめに
Twitter OAuth 2.0の認可の仕組みを利用して、Webアプリを作る場合、どういうアーキテクチャがいいか検討してみました。表題の通り雑です。またセキュリティ的にも裏が取れているわけではないので、参考程度にお願いします。
構成
トークンの扱い検討
方法はざっくり以下の3つ(雑すぎ)。3がいいかなぁと思いシーケンスを書いてみる
- Authraizationヘッダー + localStorage
=> XSS怖い - Authraizationヘッダー + Cookie(not HTTP Only属性)
=> CSRF怖いのでAuthraizationヘッダーを使うと、CookieにHTTP only属性は使えない。。(XSS怖い) - Cookie認証 + Cookie(HTTP Only属性+Same site(Lax,Strict))
=> XSS,CSRF対策出来てそう
シーケンス
補足事項
- Twitter OAuth 2.0は、
OAuth 2.0 Authorization Code Flow with PKCE
というフローを採用している - Cloudflare Functionsを使って、クラサバを同一ドメインにしている
- SetCookieは、SameSite=Lax;Secure;HttpOnly;を付与
(1) User-Agentとサーバーサイド間をセッション管理しつつ、サーバサイドでaccessToken,refreshTokenを保持する
編集中
(2) CookieにaccessToken,refreshTokenを保持する場合(非推奨)
※1
もやもや箇所。Twitterに遷移してしまうため、永続領域に書き込まないといけない。code_verifierの格納は、secure属性とSameSite=Laxを付与。HttpOnly属性はJSからなので付与できない。プラスで適切なexpire時間を設定する。
document.cookie="code_verifier=hoge;secure;SameSite=Lax"
※2
scopeは以下の通り
- /2/users/meエンドポイントが実行できる ...
users.read
tweet.read
- refresh tokeの取得 ...
offline.access
※3
Twitterには、Public ClientとConfidetial Clientが指定できます。サーバーサイドで安全にClientSecretを運用できる今回のケースでは、Confidetial Clientでいいかなと思いました。Public Clientの場合、Authorization: Basic
ヘッダーを利用せず、ClientSecretも利用しません。Confidetial Clientを指定すると、Public Clientのトークン取得方法が利用できませんが、逆は可能みたいです。
※4
Rate limitsとUsers lookupを参照。アプリレート制限とユーザーレート制限があり、別で計算される
- ユーザーレート制限
- 認証されたユーザー毎に15分間に75リクエスト
- アプリレート制限
- アプリのOAuth 2.0ベアラートークンは、15分間に900リクエスト
留意点
アクセストークンのライフサイクル
項目 | 値 |
---|---|
アクセストークンの期限 | 2(h) |
リフレッシュトークンの期限 | 不明 |
トークンの無効化
Authenticationより、/2/oauth2/revoke
エンドポイントが用意されている。token_type_hint
でアクセストークンもしくはリフレッシュトークンを利用して、トークンをrevokeできる。revokeされるのは両方のトークン。
$ curl --location --request POST 'https://api.twitter.com/2/oauth2/revoke' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--basic -u '<ClientId>:<ClientSecret>' \
--data-urlencode 'token_type_hint=refresh_token' \
# --data-urlencode 'token_type_hint=access_token' \
--data-urlencode 'token=xxx'
さいごに
実際にこの構成でアプリを作ってみるので、更新情報があればまた書こうと思います。仕事で公開されているPOSTのAPIのHTTPレスポンスヘッダー(Access-Control-Allow-Origin
)に呼び出し元を指定して、CSRF対策したのを思い出した。