※タイトル変更しました。
(前タイトル:Rubyでのgemを使わないtwitterのoauth2用tokenの取得)
oauthの仕組みとrubyに慣れるため、twitterのoauth2用tokenの取得を自前で実装してみました。
検証は中途半端ですがメモがてら
ソースコード
def twitter_auth
api_key = '0Z2...........ANu'
api_secret = 'EG50c.................................FYGvt'
encoded_key = URI.encode(api_key)
encoded_secret = URI.encode(api_secret)
bearer_token = encoded_key + ":" + encoded_secret
base64_token = Base64.strict_encode64(bearer_token)
twitter_uri = URI.parse('https://api.twitter.com/oauth2/token')
https = Net::HTTP.new(twitter_uri.host, twitter_uri.port)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Post.new(twitter_uri)
req["Authorization"] = "Basic #{base64_token}"
req.content_type = 'application/x-www-form-urlencoded;charset=UTF-8'
https.set_debug_output $stderr
res = https.request(req, body = 'grant_type=client_credentials')
render text: res.body
end
はまった事
[事象]
https://api.twitter.com/oauth2/token の実行が上手く出来ない。
コーディングの過程で
リクエスト結果が
403エラー {"errors":[{"code":99,"message":"Unable to verify your credentials","label":"authenticity_token_error"}]}
400エラー が返ってくる。
[原因1]
リクエストヘッダ、Authorizationの値(Base64エンコーディングされてる)に\nが混ざっていた。
a)Base64エンコーディングの仕様の違いにより、リクエストヘッダの値が正しくデコードできない
当初利用していたrubyのBase64.encode(str)はRFC 2045に基づいており、1行あたりの文字数制限が存在するため、改行コードが入りうる。
一方でBase64.strict_encode64(str)はRFC 4648に基づいており、改行コードが入らない。
twitter側でのデコードの際、エンコーディングの違いにより、正しくデコードできなかった。
[原因2]
b)リクエストヘッダ内の改行コードが入ると、rubyのPOSTリクエストがおかしくなる?
・ruby
Authorizationの値に
\nが入った場合:ステータス400
誤った値の場合:ステータス403
正しい値の場合:ステータス200
が返ってくる。
・curl
Authorizationの値に
\nが入った場合:ステータス403
誤った値の場合:ステータス403
正しい値の場合:ステータス200
が返ってくる。
上記のように、rubyとcurlでは\nが入った場合のステータスが異なる。
どちらのPOSTリクエストが正しいかは不明ではあるが、
rubyの場合改行コードがリクエストヘッダに含まれると、意図しないリクエストが送出されるように思える。
この辺はhttpリクエストのキャプチャツールを使えば判りそうではあるが、今回は放置。
[混乱の元]
POSTリクエスト実装前の、Curlでの試験時、
p base64_token、ではなく
render text: base64_token で取得したtokenを利用したため、
bearer_tokenの値が
本来の、
MFo(省略)kZSQ2Zv\nT1RMS(省略)d2dA==
ではなく、
MFo(省略)kZSQ2Zv T1RMS(省略)d2dA==
(\nが半角スペースになっていたもの)を利用していた。
base64の値をデコードする際は、A–Z, a–z, 0–9 までの62文字と、記号2つ (+, /)、パディング記号(=)以外は無視されるみたいなので、半角スペースを含むtokenでは問題なくAPIを実行できていた様子。