TwitterのOAuth2.0 Betaためしてみた!
※正式提供版における設定や動作については以下の記事として公開しております。
はじめに
TwitterがOAuth2.0のベータ版をリリースしたとのことで、ベータプログラムに参加して実際に利用してみました。
今回は動作を細かく確認したいのでライブラリを利用せずにcurlで実施しています。
認可リクエスト
まず認可リクエストを組み立て、ブラウザからアクセスします。
認可リクエストの各パラメーターについては、公式ドキュメントのParametersを参考にすると良いでしょう。
なお、今回は以下のような認可リクエストになりました。基本的にOAuth2.0に準拠したパラメーターなので詳細は省きますが簡単に補足します。
https://twitter.com/i/oauth2/authorize?response_type=code&client_id=<クライアントID>&redirect_uri=https://127.0.0.1:3000/auth/twitter/callback&scope=tweet.read%20users.read%20account.follows.read%20account.follows.write%20offline.access&state=abc&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=s256
-
response_type
現状"code"固定のようです。 -
client_id
ベータプログラムに参加することでDeveloper Portalから確認できるようになるので、その値を指定します。
-
redirect_uri
OAuth1.0用に設定していたCALLBAK URLSの値が共通で利用されます。
-
scope
定義されているスコープの中から必要なものを指定します。
各エンドポイントに対して必要なスコープも公式のEndpointsに記載があります。
https://developer.twitter.com/en/docs/twitter-api/oauth2 -
state
CSRF対策用のパラメーターです。今回はサンプルなので推測可能な値を設定していますが、実際に利用する際はランダムな値を指定してください。 -
code_challenge
code_verifier
を後述するcode_challenge_method
で計算した値を指定します。
公式のドキュメントに記載されていた以下のOnline PKCE Generatorを利用した場合は以下のようになります。
なお、Code VerifierはRFC 7636の記載にもとづい43文字から128文字の範囲で指定します。
今回はRFC 7636の「Appendix B. Example for the S256 code_challenge_method」に記載されている値をそのまま利用します。実際は推測不可能なランダムな文字列を利用するようにしてください。 -
code_challenge_method
plain
とs256
が利用可能です。
RFC7636のSecurity Considerationsにも記載がありますが、特別な理由がなければplain
は利用すべきではないでしょう。
同意画面
認可リクエストのURLにアクセスすると以下のような同意画面が出ます。スコープにもとづいて権限が要求されているので、確認して[Authorize app]
を押下します。
認可レスポンス
[Authorize app]
を押下すると、以下のような事前に指定したリダイレクトURLにリダイレクトされます。
https://127.0.0.1:3000/auth/twitter/callback?state=abc&code=X2luZ2ZxTUxLWFhqTl9RYkpKWXUzSWhzOE1HbkMyV1hvd0wwWEJHX2dTUGp2OjE2MzEzNzA3Njg1Mzc6MToxOmFjOjE
URL中のcode
パラメーターが認可コードなのでアクセストークンを取得するために後ほど利用します。
また、今回は省いていますが、実際にはここでstate
パラメーターを検証します。
アクセストークンリクエスト
さきほどの認可コードを利用して以下のようなリクエストを送信することでアクセストークンを取得します。
$ curl --location --request POST 'https://api.twitter.com/2/oauth2/token' \--header 'Content-Type: application/x-www-form-urlencoded' \--data-urlencode 'code=X2luZ2ZxTUxLWFhqTl9RYkpKWXUzSWhzOE1HbkMyV1hvd0wwWEJHX2dTUGp2OjE2MzEzNzA3Njg1Mzc6MToxOmFjOjE' \--data-urlencode 'grant_type=authorization_code' \--data-urlencode 'client_id=<クライアントID>' \--data-urlencode 'redirect_uri=https://127.0.0.1:3000/auth/twitter/callback' \--data-urlencode 'code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'
{
"token_type": "bearer",
"expires_in": 7200,
"access_token": "<アクセストークン>",
"scope": "offline.access account.follows.write users.read account.follows.read tweet.read",
"refresh_token": "<リフレッシュトークン>"
}
注意点としては、認可コードの有効期限が30秒しかないので手動で実施しているとうっかり有効期限切れしてしまいます。また、現状クライアントに対してConfidentialまたはPublicの指定ができず、トークンエンドポイントに対して認証はかけられていないようなのでclient_secret
の指定はありません。
APIリクエスト
取得したアクセストークンを用いてAPI仕様書に従ってリクエストすることで正常応答が得られます。
$ curl --location --request GET 'https://api.twitter.com/2/users/1338063849413472258' \--header 'Authorization: Bearer <アクセストークン>' | jq
{
"data": {
"id": "1338063849413472258",
"name": "56 dev",
"username": "kgoro_dev"
}
}
なお、多くのAPIで指定する必要があるid
は適当なサービスで検索できました。
また、リクエストに関しては、以下のGitHub Gistに色々まとめられていたので、公式と合わせて参照すると良いかもしれません。
アクセストークンの更新
認可リクエストにおいてscopeとしてoffline.access
を要求することで、アクセストークンリクエストのレスポンスとしてリフレッシュトークンを取得することができます。
リフレッシュトークンを利用して以下のようなリクエストをトークンエンドポイントに送信することでアクセストークンを更新することができます。
$ curl --location --request POST 'https://api.twitter.com/2/oauth2/token' \--header 'Content-Type: application/x-www-form-urlencoded' \--data-urlencode 'refresh_token=<リフレッシュトークン>' \--data-urlencode 'grant_type=refresh_token' \--data-urlencode 'client_id=<クライアントID>'
{
"token_type": "bearer",
"expires_in": 7200,
"access_token": "<アクセストークン>",
"scope": "offline.access account.follows.write users.read account.follows.read tweet.read",
"refresh_token": "<リフレッシュトークン>"
}
なお、インプリシットグラントにおいてリフレッシュトークンを発行してはならないことからも、クライアント認証できないPublic Clientに対してリフレッシュトークンを発行するべきではないでしょう。
基本的にリフレッシュトークンはSender Constrained Tokenであり、Confidential Clientに対して発行した場合、認可サーバーはクライアント認証してリフレッシュトークンが確かにそのクライアントに対して発行されたものであることを確認しなければならないことが仕様に明記されています。 しかし、現状のTwitterの実装ではクライアント認証なしでリフレッシュトークンを利用することができるため、リフレッシュトークン漏洩時のリスクが高いと言えます。おわりに
今回はTwitterのOAuth2.0 Betaを試してみました。
まだまだ気になる箇所や実装が足りていない?箇所がありますが、せっかくなのでフィードバックしていこうと思います。
Discussion
scopeにoffline_accessを追加したらrefresh_tokenを取得できそうですが、クライアント認証がないとなるとgrant_type=refresh_tokenがSender-Constrainedではなくなるので漏洩時のリスクが上がりそうですね。
コメントありがとうございます。リフレッシュトークンの利用について追記させていただきました。