TwitterAPIを使ってOAuth2.0のフロー(Client Credentials)を確認した。

先日、以下のエントリーにて、4つあるOAuth2.0の認可フロー(Grant Type)からAuthorization Codeの流れを確認しました。

takapi86.hatenablog.com

今回は、TwitterAPIにOAuth2.0でツイートの検索ができるよう認可してもらい、実際に検索結果のjsonが返ってくるところまでやっていきたいと思います。

Client Credentialsの流れは動画で確認できます。

www.youtube.com

参考

やること・ゴール

  • 前回同様、Rubyで簡易的な実装で流れを掴んで行きたいと思います。
  • 上記にも書きましたが、TwitterAPIにOAuth2.0でツイートの検索ができるよう認可してもらい、実際に検索結果のjsonが返ってくるところまでやっていきたいと思います。

Client Credentialsについて

Client Credentialsは他の認証フロー3つとは、少し異なります。

  • ユーザ
  • リソースを保持するサービス・認可をするサービス
  • 第三者(リソースを保持するサービスのリソースを使いたい)

上記3人の登場人物がいたとすると、Client Credentials以外の認証フロー(Authorization Code, Implicit, Resource owner password credentials)は、 第三者がリソースへのアクセスの認可をしてもらうためのものです。 それに対して、Client Credentialsは認可を必要としていないリソースへアクセスする場合に使用します。

具体的にどういうこと?というと、 例えば、今回実装するTwitterAPIでは、 ‘Application-only authentication’ という認可のタイプ、以下の操作をすることが許可されます。 (TwitterAPIでは、この認可タイプ以外は、OAuth2.0に対応していないようです。)

  • ツイートの検索
  • ユーザのツイートの取得
  • ユーザー情報を取得
  • 任意のアカウントの友人やフォロワーの取得

など

反対にアクセスできないものは、

  • ツイートの投稿
  • ダイレクトメッセージの送信

など

つまり、ユーザ認可が必要のない公開されている内容のみ使用したい場合に使います。

恐らくアクセス数の制御のためだと思われます。

大まかな流れ

Client Credentials の説明を上記で行った通り、今回TwitterAPIでは、 ‘Application-only authentication’ の認可をもらいます。

流れとしては以下です。公式ページの流れに沿って実装していきます。

Application-only authentication — Twitter Developers

  • consumer_keyとconsumer_secretを取得する
  • consumer_keyとconsumer_secretをBase64エンコードし、bearer_tokenを取得する
  • bearer_tokenを使って、特定のアカウントのツイート一覧を表示する

consumer_keyとconsumer_secretを取得する

Twitter Developersにログインし、 consumer_keyとconsumer_secretをもらいます。 手順は検索すると多くの記事がでてくるので割愛します。

consumer_keyとconsumer_secretをBase64エンコードし、bearer_tokenを取得する

ここは公式ページの Step 1: Encode consumer key and secret, Step 2: Obtain a bearer token に該当します。

以下のコードにあるように、consumer_key, consumer_secretをURIエンコードし、 : で結合後、Base64エンコーディングし、リクエストを送信します。

# -*- coding: utf-8 -*-

require 'uri'
require 'net/http'
require 'openssl'
require 'base64'

consumer_key = URI.encode({ consumer_key })
consumer_secret = URI.encode({ consumer_secret })

credential = Base64.strict_encode64(consumer_key + ':' + consumer_secret)

uri = URI.parse('https://api.twitter.com/oauth2/token')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true

request_body_params = 'grant_type=client_credentials'
request_header = {
  'Authorization': "Basic #{credential}",
  'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
  'Content-Length': request_body_params.length.to_s,
  'Accept-Encoding': 'gzip'
}

request = Net::HTTP::Post.new(uri.request_uri, request_header)
request.body = request_body_params

response = https.request(request)

puts response.code
puts response.body

成功するとステータスコード200で以下のレスポンスが返ってきます。 access_tokenbearer_token です。

{
  "token_type":"bearer",
  "access_token": { ここにアクセストークンが表示されます。 }
}

bearer_tokenを使って、特定のアカウントのツイート一覧を表示する

ここは公式ページの Step 3: Authenticate API requests with the bearer token に該当します。 ひとまず、公式のサンプル通りに実装していきます。

# -*- coding: utf-8 -*-

require 'uri'
require 'net/http'

access_token = { access_token }

uri = URI.parse('https://api.twitter.com/1.1/statuses/user_timeline.json')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true

request_header = {
  'Authorization': "Bearer #{access_token}",
  'Accept-Encoding': 'gzip'
}
request_params = {
  count: '100',
  screen_name: 'twitterapi'
}

uri.query = URI.encode_www_form(request_params)
request = Net::HTTP::Get.new(uri.request_uri, request_header)

response = https.request(request)

puts response.code
puts response.body

成功するとステータスコード200でそれっぽいレスポンスがjsonで返ってきます。

せっかくなので、自分のツイートの検索してみます。 パラメータの仕様はこちらで確認しました。

GET search/tweets — Twitter Developers

# -*- coding: utf-8 -*-

require 'uri'
require 'net/http'

access_token = { access_token }

uri = URI.parse('https://api.twitter.com/1.1/search/tweets.json')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true

request_header = {
  'Authorization': "Bearer #{access_token}",
  'Accept-Encoding': 'gzip'
}
request_params = {
  q: '腹痛に耐えながらnginxをビルドし直し自サービスをhttp2化した。',
  lang: 'ja',
  result_type: 'mixed',
  count: '1'
}

uri.query = URI.encode_www_form(request_params)
request = Net::HTTP::Get.new(uri.request_uri, request_header)

response = https.request(request)

puts response.code
puts response.body

結果のjsonはちゃんと見ていませんが screen_name に自分のアカウントが表示されていたので良さそうな気がします。

以上で、一通りの流れを確認しました。 今後も様々な認証・APIに触れて、API実装力を鍛えていきたい次第です。