GoでTwitter APIのOAuth 2.0 Authorization Code Flow with PKCEを叩く
概要
Twitter APIのOAuth 2.0 Authorization Code Flow with PKCEをcode_verifierとcode_challengeを生成して叩いている記事が見つからなかったので、実際に生成しつつTwitterクライアントライブラリで叩いてみました。
なお、この記事ではクライアントという単語はOAuth2.0クライアントのことを指します。
OAuth 2.0 Authorization Code Flow with PKCE
OAuth 2.0 Authorization Code Flow with PKCEはTwitter APIの認証方法の一つです。ツイートの検索などログインしなくてもできる処理はクライアントのみ(OAuth 2.0 Bearer Token (app-only))で実行できます。
一方でアカウントのフォローやリツイートなどの操作は「誰が行ったか」の情報が必要です。この場合、リツイートなどの操作を実行するアカウントによってクライアントを認証する機能なければ、クライアントが操作を行うことはできません。
そこでOAuth 2.0 Authorization Code Flow with PKCEを利用します。OAuth 2.0 Authorization Code Flow with PKCEはAuthorization Code FlowをPKCEで拡張した方式です。 では以下のように定義されています。
An extension to the authorization code flow to prevent several attacks and to be able to perform the OAuth exchange from public clients securely.
Authorization Code Flow(認可コードフロー)はOAuth2.0の認可フローの一つです。Client Secretを使い、認証の機能を持ちます。ここでは詳しいフローを書きませんが、詳しくはAuthleteの川崎さんの記事などが参考になります。
PKCE(pixyと発音するらしい)とはProof Key for Code Exchangeの略で、Public Clientを認可コード横取り攻撃から認可コードフローを保護する拡張です。詳しい仕様は
のサイトが参考になりました。
Public Client
今回はPublic Clientではなく、Confidential Clientを使用しています。二つの大きな違いはClient Secretを使えるかどうかですが、今回はあまり意識する必要がありません。
この拡張は以下のパラメータを新しく定義します。
code_verifier
43文字〜128文字のURLセーフな文字列
code_challenge_method
S256
かplain
の文字列
code_challenge
code_challenge_method=plain
の場合はcode_verifierそのもの。
code_challenge_method=S256
の場合はcode_verifierのsha256によるハッシュ値をbase64 urlエンコードしたもの。
codeVerifier
とcodeChallenge
の使用方法についてざっくり述べると
- クライアントは認可サーバーの認可エンドポイントへのリクエストの際、
code_challenge
をクエリストリングに含める。 - サーバーはクエリストリングから
code_challenge
を取得し、データベースに保存する。 - クライアントは認可サーバーのトークンエンドポイントへのリクエストの際、
code_verifier
をリクエストボディに含めて送信する。 - サーバーは
code_verifier
からcode_challenge
を計算し、2でデータベースに保存しておいたcode_challenge
と比較して等しければクライアントのリクエストを受理する。
code_challenge_method
はS256
が推奨されます。なぜなら、code_challenge
はクエリストリングとして利用される値であり、暗号化されることなく通信路を流れるため、code_challenge=code_verifier
だと、簡単に盗聴されてしまいます。
前準備
このコードを実行するためにはTwitter Developer PortalTwitter側で設定をし、
- Redirect URI
- Client Secret
- Client ID
のパラメータを指定する必要があります。この指定については以下の記事がとても参考になりました。
なお、今回のソースではRedirect URIはhttp://localhost:3000/callback
であると仮定します。
パラメータの生成
今回使用するコードのソースです。
今回はcode_challenge_methodはS256
に固定します。 つまり、code_challengeはcode_verifierのハッシュ値になります。3つのパラメータを生成しているのはソースコードのうち、以下の部分です。
state
は認可コードフローで認可コードフローで攻撃を検知するためのパラメータです。詳しくはこちらなどを参考になりました。
それではPKCEの各パラメータの生成方法を確認します。code_verifierはRFCでは
NOTE: The code verifier SHOULD have enough entropy to make it
impractical to guess the value. It is RECOMMENDED that the output of
a suitable random number generator be used to create a 32-octet
sequence. The octet sequence is then base64url-encoded to produce a
43-octet URL safe string to use as the code verifier.
とあるので、これに倣って32オクテット(バイト)の乱数を生成してbase64 URLエンコードすることで生成しています。そして、codeChallenge
はcodeChallengeMethod
に従い、sha256でハッシュ値のバイト列にして、それをbase64URLエンコーディングしています。
実際に3つのパラメータを利用しているのはソースの以下の部分です。
buildAuthzURL
、つまり認可エンドポイントへのリクエスト時にcode_challenge
を含め、buildTokenRequest
、つまりトークンエンドポイントへのリクエスト時にcode_verifier
を含めています。
テスト
twitter v2のクライアントライブラリとして以下を利用します。
環境変数の読み取りには以下を参考に、godotenvを使いました。
叩くTwitter v2 APIは がまだgotwtrでは実装されていないので を使います。
では、試しに自分の以下のツイートを取得してみます。実行方法については を参考にしてください。
❯ go run main.go
{1493108554618015752 俺、修論終わったら本気出すんだ <nil> [] <nil> <nil> <nil> <nil> false <nil> <nil> [] <nil>}
取得できました。他のAPIを叩きたい場合、必要なスコープが違うので、各APIのOAuth 2.0 scopes required by this endpointを参考にして、28行目のScopes
を書き換える必要があります。
まとめ
OAuth 2.0 Bearer Token (app-only)だとベアラートークンを投げつけるだけなのですが、OAuth 2.0 Authorization Code Flow with PKCEを使うとなると結構難しいですね、、
間違いや質問等あったらコメントください!
参考にした記事
Author And Source
この問題について(GoでTwitter APIのOAuth 2.0 Authorization Code Flow with PKCEを叩く), 我々は、より多くの情報をここで見つけました https://zenn.dev/senk/articles/1eaf89b5a26426著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Collection and Share based on the CC protocol