Twitterbotを作ってみているのでその時のメモ。 あくまで個人的なメモであり、網羅的な解説などをするものではないです。
方針
なるべく新しいものを使いたいと思ったので、TwitterAPI v2 + OAuth 2.0 を使うことにした。
TwitterAPI v2 は 2022-11-15 にプライマリ API に指定された。まだ一部 1.1 にあって 2.0 にはない APIもあるようだが、基本的には 2.0 を使っていくのがよさそうだ。
OAuth はどうも、App レベルのアクセスは 2.0 でユーザーレベルのアクセスは 1.0a みたいに使い分けることもできるらしい。 が、調べながらやった結果、その辺りをちゃんと把握せずに進めてしまい、今回は 2.0 だけでやるようにしてしまったので一旦その方向で進めている。
bot用のアカウントを作る
bot用に新しく Twitterアカウントを作る。 未ログインの状態で Twitterトップページから通常の手順で作れば問題ない。
色々挙動を確認したりするのに便利なので、運用に使うアカウントとは別にデバッグ用のアカウントを用意すると便利だ。一度 botの運用を開始すると下手なテストができなくなる。
アカウントに電話番号を登録する
TwitterAPIを使うためには Twitterアカウントを開発者アカウントに登録する必要があるが、そのためには Twitterアカウントに電話番号を登録する必要がある。同じ電話番号を複数のアカウントに登録しても問題ないようなので、複数の botを作る場合でも電話番号は 1 つで問題なさそうである。
一般的な手順通り、Twitterのログイン時の画面の左メニューから「もっと見る」「設定とプライバシー」「アカウント」「アカウント情報」でパスワードの確認が入るのでパスワードを入力し、「電話」「電話番号を追加」で行う。 番号を入力すると SMS で認証コードが送られてくるので入力すると登録できる。
なお、下記手順で開発者アカウントを有効にした後に試しにデバッグ用のアカウントに登録した電話番号の登録を消してみたが、今のところは問題なく APIは使えている。もしかしたら何かのタイミングで使えなくなる可能性はあるかもしれない。
開発者アカウントを有効にする
Twitterアカウントを開発者アカウントに登録する。
開発者アカウントに登録したい Twitterアカウントにログインした状態で https://developer.twitter.com/にアクセスし、右上の Sign up ボタンを押す。
名前、国、利用目的(選択式)、政府が使うものかどうか(?)、更新情報をメールで受け取るかを選んで下部の Next を押し、次の画面で Developer agreement & policy に同意するチェックボックスにチェックを入れて Submit を押す。
最後にメールアドレスの検証があるので、登録したメールアドレスに届いた検証メールを探して Confirm your email を押せば APIの利用を開始できる。
開発者アカウントにはアクセスレベルがあり、一番簡単な(制限が強い) Essential accessであればこれだけで使える。以前は申請理由について英作文をする必要があったようだが、今はここまでなら必要はない。
App を登録する
検証メールから Confirm your email を押すと、App の名前を入力するページに飛ばされる。
アプリ名はグローバルでユニークである必要があるが、後から変更できるので適当な名前でもよい。日本語でも大丈夫。
名前は OAuth の認可画面やツイート時の source
情報に使われる模様。
アプリ名を入力すると「API Key」「API Key Secret」「Bearer Token」が得られる。なくさないように保管する。
APIを呼び出してみる
Bearer Token を使うと、ユーザーに紐付かない APIを呼び出すことができる。
❯ curl -s -H "Authorization: bearer ${TWITTER_APP_BEARER_TOKEN}" 'https://api.twitter.com/2/users/by?usernames=thinca' {"data":[{"id":"15676452","name":"thinca","username":"thinca"}]}
OAuth 2.0 を有効にする
API経由で botアカウントでツイート等を行うには、OAuth を使ってアカウントから App に認可を与える。 Developer Portalの左のメニューの Projects & Apps からプロジェクト内の Apps を選び、「User authentication settings」から「Set up」を押す。
OAuth 2.0 を有効にして、アプリのタイプを選ぶ。今回は botを作るので「Automated App or bot」を選ぶ。
「Callback URI / Redirect URL」と「Website URL」を設定する。
これは一般ユーザー向けに認可を行いたい場合はきちんと Web アプリを用意する必要があるが、今回は botアカウントだけでよいので手動でがんばればなんとかなる。
Callback URIには適当に http://localhost/
を設定(この URL に token 等が渡るので外部の URL にしてはいけない)。Website URL には http://example.com/
などを適当に設定する。
すると「Client ID」と「Client Secret」が手に入るのでこれをなくさないように保管する。
OAuth 2.0 で botに権限を与える
認可用の URL を作る。
type
=code
固定client_id
= 先ほど生成した Client IDredirect_uri
= 先ほど Callback URI / Redirect URL に登録したものscope
= 許可を与えるスコープのスペース(%20
)区切りのリストcode_challenge
= ちゃんとやる場合はランダムに生成する必要があるが、今回は固定でchallenge
code_challenge_method
= ちゃんとやる場合はS256
とかを指定するが、今回はplain
https://twitter.com/i/oauth2/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=http://localhost/&scope=tweet.read%20users.read%20tweet.write&state=state&code_challenge=challenge&code_challenge_method=plain
botのアカウントでログインした状態で作った URL にアクセスすると、認可のための画面になる。
「アプリにアクセスを許可」を押すと、Redirect URIに指定した URIにパラメータ付きでリダイレクトされる。
本来はここで Web アプリがリクエストを受け取り、サーバで処理を行う。
が、今回はともかく botの認可だけできればいいので、リダイレクトされた先(localhostだと当然サーバが動いていなければ接続エラーになるが、URL さえわかればよいので問題はない)の URL の code=
の部分に現れたコードを使って以下のように HTTP リクエストを手動で発行する。
${CLIENT_ID}
と ${CLIENT_SECRET}
にはそれぞれ Client ID と Client Secret を、${CODE}
にはリダイレクトされた URL から得たコードを入れる。code_verifier
にはちゃんとやる場合は計算して出した verifier を入れる必要があるが、今回は plain で値を固定しているのでそのまま先ほどの challenge
を入れる。
なお、この ${CODE}
の寿命はとても短いので、今回のように手動で行う場合は急いで行う必要がある。ちゃんと計測していないが数分で切れているように思う。
curl --location --request POST 'https://api.twitter.com/2/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --basic -u "${CLIENT_ID}:${CLIENT_SECRET}" \ --data-urlencode "code=${CODE}" \ --data-urlencode 'grant_type=authorization_code' \ --data-urlencode "client_id=${CLIENT_ID}" \ --data-urlencode 'redirect_uri=http://localhost/' \ --data-urlencode 'code_verifier=challenge'
ちなみにここで Basic 認証をしているが、OAuth 2.0 を有効にした際に選んだアプリのタイプ(今回は Automated App or botを選んでいる)によっては不要になるそうだが、今回は試していない。Confidential Client に分類されるタイプの場合は必要で、Public Client に分類されるタイプは不要らしい。
すると以下のように Access Token が得られる。Access Token は寿命が短く、7200 秒(2 時間)で切れる。
{"token_type":"bearer","expires_in":7200,"access_token":"dEVDdWkxQnVZT184RlhZM0RQdHp6SjA3S2ExQmVQWG5KOTNvWkdmdGdueTh5OjE2NDE4MjEwOTYwNDM6MTowOmF0OjE","scope":"tweet.write users.read tweet.read"}
この Access Token を以下のように Authorization
ヘッダに渡すことでユーザーとして APIを利用できる。
以下は認証しているユーザー自身の情報を返す APIを利用する例。
curl -H 'Authorization: bearer dEVDdWkxQnVZT184RlhZM0RQdHp6SjA3S2ExQmVQWG5KOTNvWkdmdGdueTh5OjE2NDE4MjEwOTYwNDM6MTowOmF0OjE' https://api.twitter.com/2/users/me
Refresh Token を使って永続的にアカウントにアクセスする
認可用の URL を作る際に、scope に offline.access
を入れておくと、Access Token 発行の際に同時に Refresh Token も発行される。
Refresh Token を使うと Access Token を再発行できる。これを使うことで再度ユーザーに認可画面を表示することなくアクセスが可能になる。
https://twitter.com/i/oauth2/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=http://localhost/&scope=tweet.read%20users.read%20tweet.write%20offline.access&state=state&code_challenge=challenge&code_challenge_method=plain
上記のように offline.access
を足した画面から発行した code を先ほどと同様に https://api.twitter.com/2/oauth2/token
に渡すと、以下のように Refresh Token も一緒に返ってくる。
{"token_type":"bearer","expires_in":7200,"access_token":"UEo2TDBIemlBUkdsVlRJNHpzMWxZekFkd24tcGFETGFmVXJOWEtKdXJJVUU0OjE2NDE4MjE3NTA4ODA6MToxOmF0OjE","scope":"tweet.write users.read tweet.read offline.access","refresh_token":"b0F1bXNtd0Q4QlpDSGg5dWVEeG82UHNIY3lGcC1RbVRUMzRZcVQ0bFpkSVhrOjE2NDE4MjE3NTA4ODA6MToxOnJ0OjE"}
Refresh Token を以下のように使えば、新しい Access Token と Refresh Token が手に入る。
curl --location --request POST 'https://api.twitter.com/2/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --basic -u "${CLIENT_ID}:${CLIENT_SECRET}" \ --data-urlencode 'refresh_token=b0F1bXNtd0Q4QlpDSGg5dWVEeG82UHNIY3lGcC1RbVRUMzRZcVQ0bFpkSVhrOjE2NDE4MjE3NTA4ODA6MToxOnJ0OjE \ --data-urlencode 'grant_type=refresh_token' \ --data-urlencode 'client_id=${CLIENT_ID}'
{"token_type":"bearer","expires_in":7200,"access_token":"aTl5MVNPMlhHSUltck5lOWFlM2lyQ3dLbGhMWnBEbUxEdl9Zdi1yWGdPMUtCOjE2NDE4MjgyMDg0ODU6MTowOmF0OjE","scope":"tweet.write users.read tweet.read offline.access","refresh_token":"TlZvNXNWT0wyMzhialRZdWloM0w5OENGc3JnZzVDYlphLTM3OXItMzVaUXgwOjE2NDE4MjgyMDg0ODU6MToxOnJ0OjE"}
新しい Access Token と Refresh Token が発行されると、古い Access Token と Refresh Token はどちらも無効になる。 実際の運用時には Access Token とその有効期限と Refresh Token を保存しておき、有効期限が切れていたら Access Token を再発行して使うことになる。
Optional: アクセスレベルを上げる
開発者アカウントに登録した直後は Essential Accessになっている。申請を行うことで、Elevated Accessにすることができる。 検索やユーザータイムライン取得などのいくつかの APIは月当たりに取得できるツイート数の上限が決まっている。Essential は 50 万だが、Elevated は 200 万になる。また、作れるアプリの数や Filtered Stream に設定できるルールの数などいくつかの点で違いがある。
ログインした状態で以下にアクセスし、「Apply for Elevated」を押す。
https://developer.twitter.com/en/portal/products/elevated
Twitterアカウント、メールアドレス、個人開発者かどうか、名前、国、コーディングスキル(承認の可否には影響しない)、更新情報をメールで受け取るかを選んで下部の「Next」を押す。
次の画面で、申請したい理由を英語で書く必要がある。最低 200 文字。用途に応じて追加でいくつか理由を書く必要がある。ここは必要であれば機械翻訳等を駆使しつつ素直に書くのがよさそう。 私の場合は具体的に作りたい botが決まっていたので、そのために制約の緩和があると助かる、みたいなことを書いたら 1 時間かかるかどうかの速度であっという間に承認された。
具体的な APIの利用について
別記事で書くかもしれないし書かないかもしれない。とりあえず現状だと、API v2 ではできないけど v1.1 ではできること、v1.1 ではできないけど v2 ではできること、どちらもある。今後の v2 のアップデートに期待したい。