色々とハマり。
TwitterのJavaScriptによるOAuth
何気に今までPHPでやっててJavaScriptではやったことなかったかも。facebookはJavaScriptばかりな気もするが。
ここが分かりやすかった。
OAuth 対応 Twitter クライアント作成メモ
実装は、Googleのoauth.jsと、sha1.jsを使ってこんな感じ
var twitterApiKey = { "consumerKey" : "xxxxxxxxxxxxxxxxx", "consumerSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "accessToken" : "", "tokenSecret" : "" }; var myTwitter = function(){ }; myTwitter.prototype.accessor = { consumerSecret: twitterApiKey.consumerSecret, tokenSecret: twitterApiKey.tokenSecret, }; myTwitter.prototype.oauthToken = { oauth_token: "", oauth_token_secret: "", oauth_callback_confirmed : "" }; myTwitter.prototype.message = { method: "get", action: "https://twitter.com/oauth/request_token", parameters: { oauth_signature_method : "HMAC-SHA1", oauth_consumer_key : twitterApiKey.consumerKey, oauth_callback : chrome.extension.getURL("oauth_callback.html") } }; myTwitter.prototype.get = function(){ var self = this; OAuth.setTimestampAndNonce(this.message); OAuth.SignatureMethod.sign(this.message, this.accessor); var target = OAuth.addToURL(this.message.action, this.message.parameters); $.ajax({ type: this.message.method, url: target }).success(function(data, status, xhr) { var _param = data.split('&'); for (var i=0, j=_param.length; i<j; i++){ var _token = _param[i].split("="); if (_token.length == 2){ self.oauthToken[_token[0]] = _token[1]; } } var authorize_url = "https://api.twitter.com/oauth/authorize"; authorize_url += "?oauth_token=" + self.oauthToken.oauth_token; }).error(function(){ console.log(arguments); }); };
どこにcallbackされるねん??
困ったのがこれ。
Google Chrome 拡張機能でOAuthを利用する方法 - おし、プログラミングを見ると、manifest.jsonにbackend_pageを付ければいいのかな?と思いきや、このプロパティはmanifestのバージョン2ではなくなったみたい。
無くなったのだけど、oauth_callback.html をExtensionのルートに入れて、
chrome-extension://ppbaaebidfcpelnieckckdjpcoebenip/oauth_callback.html
とかやるとアクセスできる。
ということはこのページにcallbackさせればいいんだと、とりえあず、OAuth.addToURL()の第二引数がパラメータっぽいので「oauth_callback : chrome.extension.getURL("oauth_callback.html")」を追加。
だけど、Twitterの「アプリ使っていいですか?」からOKボタンを押しても戻ってこない。blankになる。。。。
あれ~と思ってデバッガ見るとなんかchrome-extension://invalid/に転送されてる・・・・。
エラーメッセージ調べてみると、manifest.jsonに
"web_accessible_resources": [ "oauth_callback.html" ],
ってやってやらないと、Webからchrome-extension://に来た場合、ダメっぽい。付けたら無事当該のChromeExtensionページを開いた。
manifest.jsonのpermissions
クロスドメインなので、permissionsプロパティに
"permissions": [ "https://twitter.com/oauth/*", "https://api.twitter.com/1.1/*" ]
の2つを追加。
Access token, Access token secret を取得してローカルに保存
先ほどcallbackされたページには、URLのQueryStringに「oauth_verifier」が付いているので、それを取得。
これを使ってAccess token, Access token secretを取得する。今度は、
https://api.twitter.com/oauth/access_tokenに問い合わせる。
今後はこのAccessTokenを使っていくのでこれをローカルストレージに保存する。
account/verify_credentialsでややハマり
GETメソッドで使える現在のaccess tokenが有効であるかどうかをチェックするAPI。
getDefaultMessage = function(){ return { method: "get", action: "", parameters: { oauth_signature_method : "HMAC-SHA1", oauth_consumer_key : twitterApiKey.consumerKey, oauth_version : "1.0" } }; }; var message = getDefaultMessage(); message.action = "https://api.twitter.com/1.1/account/verify_credentials.json"; message.parameters.oauth_token = oauth_token; var accessor = { consumerSecret: "コンシューマシークレットキー", tokenSecret: "アクセストークンシークレット" }; OAuth.setTimestampAndNonce(message); // ここでパラメータにnonceとtimestampを追加 OAuth.SignatureMethod.sign(message, accessor); // ここでシグネチャを追加 var target = OAuth.addToURL(message.action, message.parameters); $.ajax({ type: "get", url: target });
ってやればいいんだけど、このときmessage.parametersに余計なQueryStringとなるものを入れてはいけない。getDefaultMessageメソッドで適当なものをどんどん追加してtwitterAPI側で取捨選択してくれると思ってたので、ハマった。
statuses/updateで大ハマり
投稿をするAPIstatuses/updateはPOSTメソッドなのである。
さて、認証に必要な7つのパラメータ
oauth_consumer_key
oauth_nonce
oauth_signature
oauth_signature_method
oauth_timestamp
oauth_token
oauth_version
はどうやって渡すのか?
POSTパラメータにしてもダメだった。Authorizationヘッダをoauth.jsでOAuth.getAuthorizationHeader("", message.parameters);として加えてもダメだった(これは本当は行けるのかもしれない。自分のやり方がダメだっただけで)。
正解はQueryStringにする。しかも、ツイート文章までQueryStringで渡す。信じられないがこれで行ける。せめてツイート文章はPOSTパラメータやろう・・・・と思ってたのが大ハマり。
なので、
var message = { method: "POST", action: "https://api.twitter.com/1.1/statuses/update.json", parameters: { oauth_signature_method: "HMAC-SHA1", oauth_consumer_key: "コンシューマーキー", oauth_token: "アクセストークン" } }; message.parameters.status = tweet; OAuth.setTimestampAndNonce(message); OAuth.SignatureMethod.sign(message, this.accessor); var target = OAuth.addToURL(message.action, message.parameters); $.ajax({ type: message.method, url: target })
こんな感じ。これでうまく行ってしまう。ウソだろー。って気がするが本当。
TwitterクライアントのOAuth対応(Javascript編) | tomatomax.netが非常に参考になりました。