cojimaru BLOG

エンジニア支援のために技術情報を発信するブログ

OAuthでTwitter連携!! 誰でもTwitterAPIが利用可能に

f:id:cojimaru-chan:20210328104302p:plain

どうも、現役エンジニアのこじまるです。
今回の記事はTweet検索ツールの続編になります。



以前Twitter APIを使って、Tweet検索ツールを作成しました。このツールはユーザが指定したワードでTweet検索し、そのTweetにいいね、リツイートをすることができます。ただ、いいね・リツイートは筆者のアカウントでしかできません。そのため、他のユーザでもいいね・リツイートができるように変更してみました。


Twitter APIのOAuth1.0の仕組みがいまいち分からない

Twitter APIのOAuth1.0での実装ってどのようにするんだろう?



この記事では、このような悩みを解決します。


※本記事ではFlaskを使ってOAuth1.0を実装しましたが、想像以上に苦労しました。なので、今後学習される方のために認証の流れを丁寧に説明します。

OAuthでTwitter連携!! 誰でもTwitterAPIが利用可能に

OAuth1.0の流れ

今回の実装ではTwitter APIを実行するまでに、OAuth1.0の認可の仕組みを導入しています。

OAuth1.0の流れ

①事前処理

②リクエストークンを取得する

③ユーザをリダイレクトする

④リクエストークンをアクセストークンに変換する

⑤SignIn後の処理

具体的には、①~④の流れでOAuth1.0の処理を行います。アクセストークンを取得して、クライアントがTwitter APIを利用できる状態にします。そして、⑤では取得したアクセストークンを利用し、Twitter APIを実行します。

f:id:cojimaru-chan:20210328100253p:plain

①事前処理

事前処理として、Twitter Developer PortalよりCallback URLを登録します。このCallback URLは、Twitter ServerがリダイレクトさせるURLになります。

f:id:cojimaru-chan:20210327172521p:plain

②リクエストークンを取得する

UserがViewに表示される下記ボタンの押下により、ViewはServerにリクエストークンの取得を要求します。
f:id:cojimaru-chan:20210327202332p:plain


リクエストークンの取得のために、Serverでは下記の形式でTwitter Serverにリクエストを送出します。ここで、oauth_callbackは必須パラメータで、①でTwitter Developer Portalに登録したCallback URLと一致する必要があります。

POST https://api.twitter.com/oauth/request_token
{
     'oauth_callback':'http://192.168.10.107:5000/main'
}


@app.route('/signin',methods=["POST"])
def postSignIn():
    consumer_key, consumer_secret = session_manager.getConsumerKey()
    twitter = OAuth1Session(consumer_key, consumer_secret)
    endpoint = "https://api.twitter.com/oauth/request_token"
    oauth_callback = "http://192.168.10.107:5000/main"
    response = twitter.post(endpoint, params={'oauth_callback':oauth_callback})
    token_dict = dict(parse_qsl(response.content.decode('utf-8')))
    authentication_endpoint = "https://api.twitter.com/oauth/authenticate?oauth_token={}".format(token_dict['oauth_token'])


③ユーザをリダイレクトする

次に、②のPOSTリクエストで取得したoauth_tokenを使用して、Twitter Serverにユーザ認証を要求します。

GET https://api.twitter.com/oauth/authenticate?oauth_token=xxxxxxxxxxxx



上記のリクエストを送出するために、リダイレクトを使って実装しました。具体的には、ResponseのStatus codeを302, ヘッダのLocationフィールドを上記のURLに設定し、Viewにレスポンスを返しています。

@app.route('/signin',methods=["POST"])
def postSignIn():
    ...
    authentication_endpoint = "https://api.twitter.com/oauth/authenticate?oauth_token={}".format(token_dict['oauth_token'])

    response = jsonify()
    response.status_code = 302
    response.headers['location'] = authentication_endpoint
    return response



ブラウザがURLにアクセスすると、下記のようにTwitterの認可ページが表示されます。筆者のツールの場合、いいね・リツイートを行うUserの情報を入力し、Twitter Serverに認証を依頼します。

f:id:cojimaru-chan:20210327205702p:plain

認証に成功すると、②で指定したCallback URLにリダイレクトします。

④リクエストークンをアクセストークンに変換する

③でリダイレクトしたURLのクエリストリングには、oauth_token, oauth_verifierが付与されています。

http://192.168.10.107:5000/main?oauth_token=xxxxxxxxxxxx&oauth_verifier=xxxxxxxxxxxx



リクエストークンをアクセストークンに変換する下記のTwitter APIでoauth_token, oauth_verifierが必須となっています。そのため、それらの情報を抽出し、下記のリクエストボディに与えます。

POST https://api.twitter.com/oauth/access_token
{
    'oauth_token':'xxxxxxxxxxxx',
    'oauth_verifier':'xxxxxxxxxxxx'
}



上記のリクエストが成功することで、oauth_token,oauth_token_secret,...が取得できます。

def generateAccessToken(self,oauth_token, oauth_verifier):
    twitter = OAuth1Session(self.cosumer_key, self.cosumer_secret)
    access_endpoint = "https://api.twitter.com/oauth/access_token"
    response = twitter.post(access_endpoint, params={'oauth_token':oauth_token,'oauth_verifier':oauth_verifier})
    access_token_dict = dict(parse_qsl(response.content.decode('utf-8')))
    self.access_token = access_token_dict['oauth_token']
    self.access_secret = access_token_dict['oauth_token_secret']

⑤サインイン後の処理

④で取得した、oauth_token,oauth_token_secretを使って、Twitter APIを実行します。

@app.route('/searchTweet',methods=["POST"])
def getTweet():
    print('Enter getTweet')
    ...
    consumer_key, consumer_secret, access_token, access_secret = session_manager.getAllKey()
    global twitter
    twitter = OAuth1Session(consumer_key, consumer_secret, access_token, access_secret)
    endpoint = "https://api.twitter.com/1.1/search/tweets.json?{}&{}&{}&{}&{}".format(q,lang,result_type,count,entities)
    res = twitter.get(endpoint)

結果


まとめ

以前作成したTweet検索ツールにOAuth1.0の認証を付与し、誰でもTweet検索を行って、いいね・Retweetを行うことをできるようにしました。OAuth1.0の仕様をあまり理解していなかったため、今回実装するのは結構苦労しました。ただ、実装したことで、それなりに理解はできたと思います。


今回実装する上で必要になりました、HTTPの知識(REST I/F、リダイレクトなど)に関しては、下記の書籍を活用して勉強しました。Web APIなどの設計・開発を行う上で必要な知識が集約されているので、もし必要であればご覧ください。