LoginSignup
2
5

More than 1 year has passed since last update.

[入門]Twitter API の OAuth2.0 ユーザー認証をライブラリに頼らずやる

Last updated at Posted at 2022-08-14

さすがにHttpリクエストをするためのライブラリは使いますよ。

お断り

筆者はOAuthなんてTwitterAPIで初めて知ったような認証認可初学者なので、情報には誤りがあるかもしれません。

誤った点があれば遠慮なく教えてください。

ステップ

公式ドキュメントのステップ番号とは対応していないので注意

  1. 🚶‍♂デベロッパーポータルからOAuth2.0を有効にし、Client IDClient Secret をメモする。
  2. 🚵アカウントの持ち主に開かせるURLを生成する
    • Client ID
    • redirect_uri (OAuth2.0有効化時に登録したもののみ可能。)
    • Scopes 細かく分けられた権限。各APIエンドポイントによって必要なスコープがある
    • code_challenge 十分にランダムな文字列。
  3. 🚗URLを踏んだ先(Twitterのページ)でアカウントの持ち主に権限のリクエストを承認してもらい、リダイレクトURLのクエリから code を拾う
  4. 🚅今までの情報を使ってアクセストークンを要求する
    • code リダイレクトurlのコード
    • redirect_uri (ステップ2と同じもの)
    • code_verifier (ステップ2のcode_challengeで使用した文字列)
    • Client IDClient Secret Basic Authorizationに使用
  5. 🚀Scope offline.access が有効の場合、トークンをリフレッシュできる。
    • refresh_token アクセストークンと一緒に取得したもの
    • Client IDClient Secret Basic Authorizationに使用

🚶‍♂️ステップ1 API管理画面で必要事項の登録

デベロッパーポータルからOAuth2.0を有効にします。

有効化時、リダイレクトURLの登録が必要となります。後のステップを読んで決めてください。わからなければ https://www.google.com にしてもいいです。

有効化後に表示される Client IDClient Secret をメモします。忘れても再発行できるので気楽に・・・

🚵 ステップ2 URL を作成する

アドレスは https://twitter.com/i/oauth2/authorize です。? 以降のクエリパラメータは次です。

Key Value
response_type codeでいいです。もっと知りたい方はOAuth2.0に詳しい人に聞いてください。
client_id あなたの Client ID です。
redirect_uri ユーザーが承認した後リダイレクトされるURIです。デベロッパーポータルで登録したものしか使えません。(後から追加もできます)
scope ユーザーに承認してもらう権限です。ここに一覧があるほか、ドキュメントの各API reference に必要なものが書いてあります。複数要求する場合はスペースで連結します。(最後にURLエンコードするのを忘れずに)
state state でいいです。もっと知りた(略
code_challenge 最後のステップでアクセストークンを要求する際に必要になります。推奨される文字数はOAuth2.0に詳しい人に(略
code_challenge_method plain でいいで(略

完成したURLをアカウントの持ち主に開いてもらいます。

例(わかりやすいように改行しています)

https://twitter.com/i/oauth2/authorize
?response_type=code
&client_id=MY_CLIENT_ID
&redirect_uri=https%3A%2F%2Fwww.google.com
&scope=tweet.read+tweet.write+list.read+list.write+users.read+offline.access
&state=state
&code_challenge=SlVQjHz2
&code_challenge_method=plain

🚗 ステップ3 リダイレクトURLからcodeを取得する。

やることは一つです。リダイレクトURLのクエリパラメーターに code=CODECODECODECODE というものがあるので、これを取得してください。

方法によって様々なリダイレクトURIが考えられます。

  • 自分でlocalhostのサーバーを立てて処理する
    この場合はリダイレクトuriは http://localhost:8000 とかですかね。
  • URLスキームをレジストリで登録してプログラムで処理する
    この場合はリダイレクトuriは my-cool-app:// などになりますね。
  • 適当なサイトにリダイレクトしてURLを標準入力にコピペする
    一番簡単です。リダイレクト後のURLをユーザーにコピーさせて、プログラムに入力してもらいます。あとはプログラムで正規表現なりライブラリなりでクエリパラメータをパースしてcodeの値を手に入れます。

いずれの場合もURIの後ろにクエリ文字列 (?state=state&code=CODECODE のようなもの) を付与したリンクが開かれますので、code の値を取得してください。例えばURLに以下の正規表現でパターンマッチを取得することで、code の値を取得できます。

code=([^?&]+) (カッコの中が欲しいコードになります。)

🚅 ステップ4 code をつかってアクセストークンを得る。

APIエンドポイント https://api.twitter.com/2/oauth2/token に対して次のリクエストを POST します。

headers

Key Value
Authorization Basic + (スペース) + base64Encode(Client ID + : + Client Secret)
Content-Type application/x-www-form-urlencoded

Body (content または Payload とも)

以下の Keyvalue のペアをURLエンコードした文字列

Key Value
code 取得したコード
grant_type authorization_code
redirect_uri ステップ2 で使用したリダイレクトURL
code_verifier ステップ2 の code_challenge と全く同じもの

注意事項として、リダイレクトされた時点から30秒以内にトークンを要求しないと invalid_request というメッセージとともに400番のレスポンスをされるということを書いておきます。

成功すると、json形式のレスポンスが帰ってきます。

{
    "token_type": "bearer",
    "expires_in": 7200,
    "access_token": "ACCESS_TOKEN_ACCESS_TOKEN_ACCESS_TOKEN_ACCESS_TOKEN",
    "scope": "list.write list.read tweet.write users.read tweet.read"
}

無事にアクセストークンを入手することができました!このアクセストークンは2時間のみ有効です。

これを使って、APIのリクエストヘッダの AuthorizationBearer ACCESS_TOKEN と設定することで、ユーザーとしてツイートしたりDMしたりすることができます。各APIによって必要なscopeが違うので注意しましょう。

🚀 ステップ5 refresh_tokenで新しいアクセストークンを得る。

2時間じゃちょっと足りない!一度権限を許可したらずっとAPIを利用し続けたい!という人も居ると思います。

ステップ2でURLを作る際、scopes を指定しました。これに offline.access というスコープを追加すると、ステップ4のレスポンスjsonに refresh_token という値が追加されます。これを用いて新たに2時間有効な access_token を得ることができます。

ステップ4 とエンドポイント・ヘッダは同じですが、bodyが違います。

Body (content または Payload とも)

以下の Keyvalue のペアをURLエンコードした文字列

Key Value
grant_type refresh_token
refresh_token ステップ4で得た refresh_token

これで、ステップ4と同じ形式のレスポンスを受け取ることができます。

おわりに

以上になります。

  1. URLを作成する。
  2. ユーザーがログインして権限を承認する。
  3. リダイレクトURLから code の値を取得する。
  4. アクセストークンをリクエストする。
  5. 必要に応じてアクセストークンをリフレッシュする。

これらのステップでアクセストークンを取得し、バンバン自動ツイートしていきましょう!

最初にも書きましたが筆者はOAuth初学者です。誤っている点があれば遠慮なく教えてください。

最後までお読み頂きありがとうございました。

Pythonソース

自作のPython関数を雑に貼り付けます。大文字の変数は環境変数から読み込んだ定数です。

tweepy や oauth2lib などの認証をやってくれるライブラリは使いませんが、jsonパーサーやurl/base64のエンコード/デコードはライブラリにやってもらっています。

権限要求ページのURLを作る

def create_url():
    challenge = ''.join([random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(64)])
    with open('tmp/tw_challenge.txt', 'w') as f:
        f.write(challenge)  # 後で使うので保存
    scopes = ['tweet.read', 'tweet.write', 'users.read', 'offline.access']
    querys = {
        'response_type': 'code',
        'client_id': CLIENT_ID,
        'redirect_uri': REDIRECT_URI,
        'scope': ' '.join(scopes),
        'state': 'state',
        'code_challenge': challenge,
        'code_challenge_method': 'plain'
    }
    
    return 'https://twitter.com/i/oauth2/authorize' + '?' + parse.urlencode(querys)

リダイレクトURLからcodeを取得する

def get_code_from_url(url):
    parsed_url = parse.urlparse(url)
    query = parsed_url.query
    query_dic = parse.parse_qs(query)
    return query_dic['code'][0]

codeからアクセストークンをリクエストする(リフレッシュ兼用)

def get_tokens(code, refresh_token=None):
    auth = base64.b64encode(str(CLIENT_ID + CLIENT_SECRET).encode()).decode()
    headers = {
        'Authorization': auth,
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    if not refresh_token:
        with open('tmp/tw_challenge.txt', 'r') as f:
            challenge = f.read().split()[0]  # code_challenge の読み込み
        data = {
            'code': code,
            'grant_type': 'authorization_code',
            'redirect_uri': REDIRECT_URI,
            'code_verifier': challenge
        }
    else:
        data = {
            'grant_type': 'refresh_token',
            'refresh_token': refresh_token
        }
    req = request.Request(
        'https://api.twitter.com/2/oauth2/token',
        headers=headers,
        data=parse.urlencode(data).encode()
    )
    with request.urlopen(req) as res:
        OA2token = json.loads(res.read())
    
    return OA2token
2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5