🔑

OAuth認証でTwitterとアプリを連携する

7 min read

Twitterを使っている人なら「〇〇にアカウントへのアクセスを許可しますか?」という文字列を見たことがあると思います。
それの実装手順を紹介します。
先人の書かれた素晴らしい記事が既に存在してはいるのですが、Twitter Developer Portalがコロコロ中身を変えることもあって情報が古くなっていることもあり、自分で書くことにしました。
Pythonでの実装例も示しています。全て繋げると実際に実行できるようになっています。

そもそも何をやっているのか

アプリ側のAPI Key/API Key Secret(Consumer Key/Secret)を用いて、ユーザー側にOAuth TokenとOAuth Token Secretを発行しています。
その過程でPOST oauth/request_tokenPOST oauth/access_tokenという2つのエンドポイントを経由します。

ちなみに

Twitterで言う「API Key」「API Key Secret」は様々な解説記事で見かける「Consumer Key」「Consumer Secret」と同義です。読み替えてもらって構いません。

手順

開発者登録をする

Twitter Developer Platformで開発者登録をします。英作文とかあったりして面倒臭いですがDeepLとかの翻訳ツールを駆使して乗り切りましょう。昔に比べたらUIもわかりやすくなっているので解説記事を読まずとも突破できると思います。
電話番号を認証したTwitterアカウントでないといけないので、そこだけ注意してください。

アプリを作る

ここではEarly AccessのAPI v2は使いません。
アプリ名を入力したら出てくるAPI KeyとAPI Key Secretは今後表示されない(再生成は可能)ので、ちゃんとメモしておきましょう。
Bearer Tokenは使いません。必要になったらそれだけ生成できるので今は放置でもいいと思います。
なお、アプリ側でOAuth Token/Secretを生成する必要はありません。

Callback URLとWebsite URLを決める

これは基本的には、どちらも開発しているWebサービスのURLにしましょう。
Website URLはこんな感じで右上のアプリ名の下に表示されます。

Callback URLには、OAuth TokenとOAuth Verifier(後述)がパラメータとしてくっついてきます。
詳しくは後述しますが、例えばhttps://callback.example.comをCallback URLに指定した場合、
https://callback.example.com?oauth_token=token文字列&oauth_verifier=verifier文字列
という形で認証画面から移ってきます。
試したいだけだからといって信用できないサイトをCallbackに指定するのはやめましょう。この仕様を知っていれば悪用できてしまいます。 Webサービスでなくとも自分の管理しているサイトが良いでしょう。
最終手段ですが、存在しないURLを指定してもURLにひっついたパラメータの文字列をコピペすることはできます。

認証用URLを生成する

API KeyとAPI Key Secretを用いて、OAuthセッションを生成します。
そのセッションでoauth/request_tokenにPOSTします。このときパラメータにoauth_callbackというキーでCallback URLを指定する必要があります。詳細は公式ドキュメントを参照してください。

以下にPythonでのrequests_oauthlibを用いた実装例を示します。

from requests_oauthlib import OAuth1Session

API_KEY = "取得したAPI Key"
API_KEY_SECRET = "取得したAPI Key Secret"

callback_url = "https://callback.example.com"
request_endpoint_url = "https://api.twitter.com/oauth/request_token"
authenticate_url = "https://api.twitter.com/oauth/authenticate"

session_req = OAuth1Session(API_KEY, API_KEY_SECRET)
response_req = session_req.post(request_endpoint_url, params={"oauth_callback": callback_url})
response_req_text = response_req.text

リクエストに成功すると、以下のような文字列が返ってきます(本当にただの文字列で、JSONではありません)。

oauth_token=token文字列&oauth_token_secret=secret文字列&oauth_callback_confirmed=true

ここで必要になるのはoauth_tokenのキー名で返ってきたtoken文字列の部分です。
&=で文字列を分割してうまいこと取り出しましょう。

oauth_token_kvstr = response_req_text.split("&")
token_dict = {x.split("=")[0]: x.split("=")[1] for x in oauth_token_kvstr}
oauth_token = token_dict["oauth_token"]

取り出せたら、先述したエンドポイントにトークンをパラメータとして繋げます。それが認証用URLです。
分かりづらいですが、つまりこういうことです。

https://api.twitter.com/oauth/authenticate?oauth_token=token文字列

プログラム上でも、単純に繋げるだけです。

print("認証URL:", f"{authenticate_url}?oauth_token={oauth_token}")

Access TokenとAccess Token Secretを取得する

上の手順で認証を済ませると、Callback URLで指定した先に飛ばされます。先述の通り、URLにはパラメータがついています。

https://callback.example.com?oauth_token=token文字列&oauth_verifier=verifier文字列

ここで必要になるのはverifier文字列にあたる部分です。サーバサイドでパラメータを受け取りましょう。
試したいだけの方は、ブラウザ上のURLバーからコピペしましょう。Callback URLを自分が管理するサイトにしている場合は、私のようにこんな感じでURLからパラメータの値を切り出してみても良いでしょう。
※別にhttps://qmainconts.dev/tokendetectorをCallback URLに指定していただいても構いませんが、動作は保証しません。私が信用できない場合はもちろん指定しないでください。

これで必要な情報が揃ったので、OAuthセッションを作ってoauth/access_tokenにPOSTします。
必要になるのはAPI Key、API Key Secret、OAuth Token、OAuth Verifierの4つです。
このとき、パラメータにはOAuth TokenとOAuth Verifierを含める必要があります(公式ドキュメント参照)。

ちなみに実装例ではOAuth Verifierだけをparamsに入れていますが、なぜかこれでも動きます。なぜなんでしょう…

oauth_verifier = input("OAuth Verifierを入力してください> ")

access_endpoint_url = "https://api.twitter.com/oauth/access_token"

session_acc = OAuth1Session(API_KEY, API_KEY_SECRET, oauth_token, oauth_verifier)
response_acc = session_acc.post(access_endpoint_url, params={"oauth_verifier": oauth_verifier})
response_acc_text = response_acc.text

成功すると、以下のような文字列が返ってきます。先程と同様、JSONではありません。

oauth_token=token文字列&oauth_token_secret=secret文字列&user_id=id文字列&screen_name=name文字列

ユーザー自身のUser IDとScreen Name、そしてTokenとSecretが返ってきます。oauth_tokenoauth_token_secretと名前がついていますが、これがAccess TokenとAccess Token Secretです。
うまいこと切り出しましょう。

access_token_kvstr = response_acc_text.split("&")
acc_token_dict = {x.split("=")[0]: x.split("=")[1] for x in access_token_kvstr}
access_token = acc_token_dict["oauth_token"]
access_token_secret = acc_token_dict["oauth_token_secret"]

print("Access Token       :", access_token)
print("Access Token Secret:", access_token_secret)
print("User ID            :", acc_token_dict["user_id"])
print("Screen Name        :", acc_token_dict["screen_name"])

これで作業は完了です。
最初に取得したAPI Key/Secretと、最後に取得したAccess Token/Secretの4つを使ってOAuthセッションを作り、TwitterのAPIを叩くことができます。
お疲れさまでした。

コード全体

載せたコードを全て繋げたものを載せておきます。

from requests_oauthlib import OAuth1Session

API_KEY = "取得したAPI Key"
API_KEY_SECRET = "取得したAPI Key Secret"

callback_url = "https://callback.example.com"
request_endpoint_url = "https://api.twitter.com/oauth/request_token"
authenticate_url = "https://api.twitter.com/oauth/authenticate"

session_req = OAuth1Session(API_KEY, API_KEY_SECRET)
response_req = session_req.post(request_endpoint_url, params={"oauth_callback": callback_url})
response_req_text = response_req.text

oauth_token_kvstr = response_req_text.split("&")
token_dict = {x.split("=")[0]: x.split("=")[1] for x in oauth_token_kvstr}
oauth_token = token_dict["oauth_token"]

print("認証URL:", f"{authenticate_url}?oauth_token={oauth_token}")

oauth_verifier = input("OAuth Verifierを入力してください> ")

access_endpoint_url = "https://api.twitter.com/oauth/access_token"

session_acc = OAuth1Session(API_KEY, API_KEY_SECRET, oauth_token, oauth_verifier)
response_acc = session_acc.post(access_endpoint_url, params={"oauth_verifier": oauth_verifier})
response_acc_text = response_acc.text

access_token_kvstr = response_acc_text.split("&")
acc_token_dict = {x.split("=")[0]: x.split("=")[1] for x in access_token_kvstr}
access_token = acc_token_dict["oauth_token"]
access_token_secret = acc_token_dict["oauth_token_secret"]

print("Access Token       :", access_token)
print("Access Token Secret:", access_token_secret)
print("User ID            :", acc_token_dict["user_id"])
print("Screen Name        :", acc_token_dict["screen_name"])

Discussion

ログインするとコメントできます