🤔

とりあえず手順だけでも理解する Twitter ログイン認証

2022/08/12に公開

コードベースでとりあえず手順だけでも Twitter の認証方式を理解したい

本記事は Twitter アカウントによるログイン認証フローをどうにか自前のアプリケーションで実装するために調べた内容の記録です。主にこちら の記事とコードを参考にさせていただきました。
手順だけでも、と書いているのは認証の仕組みそのものやセキュリティの担保などについては触れないからです。

Twitter の認証方式について

https://developer.twitter.com/ja/docs/authentication/overview
Twitter の認証方式は様々で、開発者が自分のアカウントを操作する場合・各ユーザーのログイン認証を利用する場合などに応じて認証方式が分かれています。
本記事ではそのうち参考元と同様に OAuth1.0a の認証方式の手順について書いていきます。
だいたいこんなイメージです。
認証の流れ

前準備

認証フローを実装するために Twitter 側で必要な作業です。
Twitter Developer Potalにて開発者登録とアプリケーション作成を行います。また、後ほど使うので CallbackURLhttp://localhost:8000/ などにしておきましょう。
※Webアプリケーションできちんと認証を実装する場合は適切な URL にする必要があります。

実装

ひとまずコード全体

(だいたいこういう記事見る人ってとりあえずコード欲しいでしょ)
bottle と requests_oauthlib と chromium のインストールが必要です。
chromium は入れられない or 入れるのが難しい場合は手動で代替できます。
また、あくまでスクリプトレベルであって Web アプリケーションに組み込めるレベルのものではないのでそこらへんはご注意を。後で触れますが Web アプリケーションで実装するにはバックエンド/フロントエンド双方で実装が必要です。

from requests_oauthlib import OAuth1Session
import webbrowser
from bottle import run, get, request

PORT = 8000
API_KEY = "<Twitter API KEY>"
API_KEY_SECRET = "<Twitter API KEY SECRET>"


callback_url = "http://localhost:8000/"
request_endpoint_url = "https://api.twitter.com/oauth/request_token"
authenticate_url = "https://api.twitter.com/oauth/authenticate"
access_endpoint_url = "https://api.twitter.com/oauth/access_token"

# リクエストトークン取得
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"]
# 認証URL作成
auth_url = f"{authenticate_url}?oauth_token={oauth_token}"
print("認証URL:", auth_url)

# ブラウザで認証URLを開く(要ブラウザ) または、標準出力に出力される認証URLをブラウザで手動で開く
webbrowser.open(auth_url)

print("start server")


@get('/')  # redirected url
def get_token():
    # クエリパラメータから oauth_verifire 取得
    oauth_verifier = request.query.oauth_verifier
    # アクセストークンリクエスト
    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("🌟")
    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"])
    return {"status": "ok"}


run(host='localhost', port=PORT, debug=True, reloader=False)

認証手順

では認証を済ませるまでの手順を一つずつ見ていきます。
おおまかな手順としては、こちらにある通りの 3STEP です。

  1. コンシューマーアプリケーションがリクエストトークンを取得するためのリクエストを作成します。
  2. ユーザーに認証してもらい、コンシューマーアプリケーションにリクエストトークンを送信します。
  3. リクエストトークンを使用可能なユーザーアクセストークンに変換します

1. API_KEY, API_KEY_SECRET を用いてリクエストトークン取得

開発者の持つ API_KEY, API_KEY_SECRET を用いてリクエストトークンの要求を行います。

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

本来この要求では OAuth1.0 に準拠するため様々なヘッダーの整理が必要ですが、
requests_oauthlib の OAuth1Session がよしなにやってくれます。

2. ユーザーに認証してもらう

ここは参考元の記事と大きく異なる部分なのですが、ブラウザで認証URL を開き Twitter の認証画面に遷移します。また、Twitter アカウントでのログイン後のリダイレクト先は最初に設定した CallbackURL になるので、 bottle で遷移先を用意します。

2.1 リクエストトークン取得のレスポンスから認証URL 組み立て

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作成
auth_url = f"{authenticate_url}?oauth_token={oauth_token}"

2.2 ブラウザでログイン(させる)

python からブラウザを開ける環境であれば、python の webbrowser を使って認証URL をブラウザで開きます。そうでない場合は標準出力に出力される認証URL を手動でブラウザで開きましょう。

# ブラウザで認証URLを開く(要ブラウザ) または、標準出力に出力される認証URLをブラウザで手動で開く
webbrowser.open(auth_url)

3. リクエストトークン→アクセストークンの変換

ブラウザで Twitter ログイン認証後、リダイレクトされるので bottle で立てたサーバーで GET リクエストを受け取るようにします。この時、クエリパラメータに含まれる oauth_verifier が次のアクセストークン取得に必要です。

3.1 リダイレクト先に返されるパラメータを取得

@get('/')  # redirected url
def get_token():
    # クエリパラメータから oauth_verifire 取得
    oauth_verifier = request.query.oauth_verifier
...中略
    return {"status": "ok"}


run(host='localhost', port=PORT, debug=True, reloader=False)

3.2 アクセストークン取得リクエスト

またしても OAuth1Sessinon がよしなにやってくれますので、 oauth_verifier を渡してアクセストークンを取得しましょう。

    # アクセストークンリクエスト
    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})

ちなみに Twitter だとアクセストークンの他に ID と Screen name も返ってきます。

参考

https://zenn.dev/kjumanenobikto/articles/86541146abba96
https://developer.twitter.com/ja/docs/authentication/guides/log-in-with-twitter
https://qiita.com/saba1024/items/a0db0fcf279243f35387

Discussion