Twitter Oauth2.0 認証のデモを作ってみた
この記事は SUPER STUDIO Advent Calendar 2022 17 日目の記事です。
初投稿になります。
株式会社 SUPER STUDIO でエンジニアをしております @uratakusan です。
ポケモン SV におけるトレーナー業務等の業務改善を行っていたら、記事を書くのが遅れました。
今回は、 Twitter Oauth2.0 認証機能のデモアプリを作りましたので、これをネタにして話せたらと思います。
デモアプリを作ったきっかけ
Twitter Oauth 2.0 Authentication が昨年末にリリースされたため、知見が欲しかったため
Twitter のクローリングを行うアプリを作ろうとしていたため
数件サンプルを探したが、認証時に暗号化されていない場合が多かったため、より実践的なコードを書いてみたかったため
誰かの圧力によってQiitaのアドベントカレンダー企画がなくなったため
Twitter Oauth 2.0 の認証処理について
Oauth 2.0 の説明については省略します。
下記の遷移図に沿って、ログイン処理が進められます
アプリが Twitter の認証 URL を生成してリダイレクト
ユーザーが Twitter の認証 URL でアプリにアクセスを許可し、アプリのリダイレクト URL へリダイレクト
リダイレクト URL にて、 Twitter API から Access Token を取得
Access Token から Twitter の情報を取得
アプリの内容
Twitter にログインし、ログインしたユーザー情報を表示
挙動確認方法
Twitter Developer Portal で V2 API を利用できる App を作成
すべて英語ですが、やり方が様々なサイトでまとまっているため省略
対象のアプリのUser authentication settings にて下記を設定
OAuth 2.0を有効化
Type of App : Web App
Callback URI / Redirect URL : http://127.0.0.1/callback
他の設定は適当に
GitHubからリポジトリを clone
.env.default をコピーして .envを作成
cp .env.default .env
.env に下記を設定
FLASK_SECRET_KEY : ランダム文字列
CLIENT_ID : Twitter Developer Portal で作成した AppのClient ID を追加
CLIENT_SECRET : Twitter Developer Portal で作成した App の Client Secret を .env に追加
source .env で環境変数を適用
Docker を起動し、http://127.0.0.1 にアクセス
実装でつまずいた点
Twitter 認証画面のリダイレクトURL生成時に認証文字列を安全に保つには?
このサンプルを作る上で一番考えた点になります。
Twitter Oauth2.0 認証を安全に利用するには、 s256 で暗号化された文字列を認証時に利用する必要があります。(暗号化しないこともできますが、セキュアにやっていきましょう)
アプリが生成した Twitter 認証画面に s256 で暗号化した文字列 ( code_challenge ) をパラメーターに追加
Twitter 認証画面からリダイレクトしたアプリの URL にて access token をリクエストする際に復号化した文字列 ( code_verifier ) を Twitter に POST
Twitter のサーバー上で↑で渡された暗号化、復号化された文字列が一致した際に access token が取得される
まず、セッションに値をもたせることでユーザー毎に固有の値をランダム文字列を保管することはできました。
実装したコードは下記になります。
# index.py
oauth = TwitterOauth()
TokenCodeManager.create_code(session)
token_code = TokenCodeManager.fetch_code(session)
login_url = oauth.get_url(token_code)
return redirect(login_url)
from services.random_string_maker import RandomStringMaker
class TokenCodeManager:
def create_code(session) -> None:
# ランダム文字列を生成
random_str = RandomStringMaker.exec()
session['token_code'] = random_str
def fetch_code(session) -> str:
return session.get('token_code')
続いて Twitter へのリダイレクト URL 生成時に暗号化をするロジックに苦労しました。
単純に sha256 かければよいのではと余裕こいていた私は 2,3 日デバッグと調査に苦しみました。。。
Python で実装する方は真似していただけると幸いです
実装したコード:services/twitter/auth.py
def __create_login_url_param_str(self, token_code: str) -> str:
# sessionに保存されたランダム文字列の暗号化
encoded_token_code = base64.b64encode(hashlib.sha256(token_code.encode('utf-8')).digest()).decode()
code_challenge = encoded_token_code.rstrip('=').replace('=', '').replace('+', '-').replace('/', '_')
# また別にランダムで文字列を渡す必要あり
state = RandomStringMaker.exec(100)
return f"response_type=code&client_id={self.CLIENT_ID}&redirect_uri={self.REDIRECT_URI}&scope=tweet.read users.read offline.access&state={state}&code_challenge={code_challenge}&code_challenge_method=s256"
結構雑に書いたため、指摘いただけると幸いです。
感想
s256 での認証について、自分の知見がなかったため、時間がかかってしまった💦
今まで認証周りの実装をあまりしたことがなかったので、今回の実装から自分の理解に進みました。
Twitter 以外での認証処理を今後実装する際にも活かせればと思います。
実際にサービスを作ろうと思ってサンプルのために実装したが、まだそこまでできていない…というのを記事を書いていて思い出しました。
冬休みは、ポケモンしながら開発も進めていければと
参考
The OAuth 2.0 Authorization Framework
この記事が気に入ったらサポートをしてみませんか?