どうも。昨日もちょっと twitter に触れましたが、今日も twitter ねたです。
前の post で、チラッと触れた OAuth 認証 (O認証認証みたいでこわい) を使ってみたくなり、自分で 0 から書いて見ました。
既存のライブラリ使えば手っ取り早いですが、仕組みを理解したかったので、やってみるだけやってみました。
結果から言うと、ものすごく面倒です。すごい時間かかりました。
(僕の文章読解能力と、typo 検出能力と、プログラミングスキルが足りなかっただけかもしれないけど)
まあ、これの実装については、各所で結構触れられていますが、まあ話を聞いただけじゃイマイチピンとこないものだったのですが、いざ実装してみたらよくわかりました。
OAuth の仕組み
OAuth の仕様については、oauth.net の Documentation に書いてあるとおりです。
Twitter に限って言えば、この辺りを見るとよいと思います。
といってもよくわからないもので、僕も最初はちんぷんかんぷんでした。
Twitter API の OAuth がどういう認証手順を踏むかを軽くまとめると...
まずは、Twitter に自分のアプリケーションの情報を申請します。
- /oauth_clients から、アプリケーションの申請をする
- Consumer key, Consumer secret が発行される
ここまでが、事前にしておくべき作業。
この先が、実際の認証になる。
- 発行された Consumer key, secret を元に、Request Token を発行してもらう。
- Request Token, Request Token Secret が発行される
- Request Token を使って、ユーザーを Twitter (Web) に誘導して、ログインしてもらい、そのアプリケーションを認証してもらう。
- Client (not Browser) であれば、このときにユーザーに 7 桁の PIN が表示される。
- その PIN (oauth_verifier) をクライアントに入力してもらう。
- Request Token, Request Token Secret, PIN の 3 つの情報を元に、Access Token を発行してもらう。
- Access Token, Access Token Secret が発行される。
ここまでが、ユーザーが最初にそのクライアントを使ったとき(または設定ファイルなどを消してしまって再度 Access Token を取得する場合) にやること。
Access Token は、無期限らしいので、クライアントは設定ファイルなどに Access Token の情報だけを保持しておけばいいことになる。(ユーザー名も、パスワードもいらない)
- Access Token を元に、Twitter の認証を行う。
- API に投げるヘッダに、Access Token, Access Token Secret を元にした OAuth の情報を付加して、認証させる。
こんな感じになります。
見てわかるとおり、Twitter のパスワードは一切クライアントに入力されませんし、保持することもありません。
ユーザーがパスワードを入力するのは、Twitter の Web サイトに誘導されて、アプリケーションを認証する時だけになります。
一度、Access Token を取得してしまえば、ただそれだけでいい。
ただ、厄介なのは、一度ユーザーを Twitter の Web サイトににアクセスさせて、そのアプリケーションを許可してもらう必要があるということ。
そして、PIN を入力してもらわなければいけないということ。
どちらかというと、OAuth は Web アプリケーション向けな実装で、デスクトップクライアントのことはあまり考えられてないというか、後付け感がたっぷりするのは気のせいだろうか。
各 Token を発行してもらうときに生成する情報
先ほどから、「~を元に~を取得する」とか書いていますが、実はここがややこしいのです。
実は、単純に GET や POST で、Token や Key を投げるわけではなく、複雑な細工が必要です。
たとえば、認証する為の第一歩になる Request Token を取得するにはこのあたりが参考になります
といっても、僕は始めてみたとき、さっぱりわかりませんでした。
そんなわけで、Twitter のサイトで紹介されていた実装例を見てやっと理解しました。
うん、ややこしい。
Request Token を取得するには、何をすればよいのか?
じゃあまずはじめに、Request Token を取得するために必要な情報は以下のとおりです。
こいつらを、GET で /oauth/request_token に投げると、Request Token とその Secret が帰ってきます。
- oauth_consumer_key:
- Twitter にアプリケーションを登録したときに発行された Consumer Key
- oauth_signature:
- シグネチャ。詳細は後述。
- oauth_signature_method:
- oauth_signature の計算方式。
- Twitter の場合 HMAC-SHA1 決め打ちっぽい。
- oauth_timestamp:
- タイムスタンプ。unix 時間な整数で。(参照)
- oauth_nonce:
- ランダムな文字列。 (参照)
- oauth_version:
- OAuth のバージョン。オプションらしい?
こんな具合なのですが...
あ、シグネチャですね、あーこいつは本当に厄介だ。
頭抱えたくないなら、さっさとこのページから脱出することをお勧めする。
(いや、これも僕が単純に頭悪いだけかもしれないけど)
oauth_signature を生成するには...
Twitter の場合は oauth_sigunature を HMAC-SHA1 で生成する必要があります。
具体的に何かというと、メッセージ認証符号 (MAC) です。
簡単に言えば、内容が改ざんされていないかチェックする為の何かです。
この鍵を生成する為に、Secret を使います。
生成する方法なのですが、Python であればちょうど hmac というモジュールがあるのでこれが使えます。
単純に hmac.new() に key と message を投げればいいだけなのですが、これがまた厄介なのです。
まず、キーに関してですが、Request Token の場合であれば Consumer Secret のみが必要です。
で、signature を生成するメッセージになるものが、投げるパラメタ (oauth_signature 自身を除く) と URL と使用する HTTP メソッドを & でくっつけたものになります。
例えば、Request Token は
- "GET" で
- "http://twitter.com/oauth/request_token" に
- "oauth_consumer_key=CONSUMER_KEY&oauth_nonce=NONCE&oauth_signature_method=HMAC-SHA1&oauth_timestamp=TIME&oauth_version=1.0" を投げるので
こんな感じになります。
- GET&http%3A%2F%2Ftwitter.com%2Foauth%2Frequest_token&oauth_consumer_key%3DCONSUMER_KEY%26oauth_nonce%3DNONCE%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3DTIME%26oauth_version%3D1.0
投げるパラメタの文字列と URL は、ちゃんとエスケープしてあげてくださいねw
Python であれば urllib.quote(string, "") を通せばおkだと思われます。
それと、必ず上記で書いた順番どおりにつなげてください!!!
ええと、早い話が要素名をソートさせた順番に並べるということです。
Python でいえば sorted() した順番にくっつけるということです。
これらの、詳しい仕様はこちら。
あとは、hmac.new() に message としてこいつを投げます。
おっと、key についての説明を忘れていましたね。
Request Token の場合は、Consumer Secret のみでいいので
- CONSUMER_SECRET&
という key になります。
(実は、Access Token とか、そのあたりになると、token を付加するので、その token の secret も必要になります)
(その場合に CONSUMER_SECRET&TOKEN_SECRET を Key にします)
Python の場合であれば、
- hmac.new(key, msg, hashlib.sha1).digest().encode("base64").strip()
とかして、帰ってきた signature を、oauth_signature に付加してあげてください。
取得したダイジェスト値を Base64 にすることを忘れずに。
そうだ、後は投げるだけだ...
後は、これらを GET で投げるだけです。
そうすると、やっと Request Token を取得できます。
やっと、です。やっと。
その後の流れ...
で、Request Token のリクエストをなげると、Token と Secret がくる。
そんでもって、ユーザーに
にアクセスしてもらう。
アクセスして、すでに Twitter にログインしてる場合はこんな画面が出てくる。
ログインしてない場合は、ログインしてもらうと、これが出てくる。
Allow を押してもらう。
こんな7桁の数字 (PIN) が表示される。
これを、ユーザーに入力してもらう。
先ほど投げたパラメタ + PIN (oauth_verifier) + Access Token を /oauth/access_token に投げる。
nonce とか timestamp は作り直す。
シグネチャも、もちろんこれらを付加して作り直す。
GET&http%3A%2F%2Ftwitter.com%2Foauth%2Faccess_token&oauth_consumer_key%3DCONSUMER_KEY%26oauth_nonce%3DNONCE%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3DTIME%26oauth_token%3DREQUEST_TOKEN%26oauth_verifier%3DPIN%26oauth_version%3D1.0
シグネチャの元になるメッセージはこんな感じ。
key は、先ほどチラッと述べたとおり "CONSUMER_SECRET&TOKEN_SECRET" になる。
それと、Authorization: OAuth という HTTP ヘッダも付加してあげないとだめっぽい?
んでもって、やっとのこと Access Token とその Secret が帰ってくるわけである。
それといっしょに、screen_name が帰ってきて、ユーザーが認証されたこともわかるわけである。
あとは、通常の API にこの Access Token とかをまたシグネチャつくったりなんやりして、それを付加して投げてあげると、いけるはずです。
ええと、Request Token は半ば一時的なものなので、捨てていいです。
Access Token と Access Token Secret は、無期限に使えるので、こいつを保存しておけば、次回からは一連の認証操作が必要なくなります。
で、API への付加の仕方ですが、やり方はまったく同じで、oauth_token に Access Token をぶちこんでやって、key も Access Token Secret を使って、シグネチャも生成してくっつけて投げてあげます。
GET でも POST でもいけるっぽい?(詳細未確認)
ががが、もっと違うやり方があって。
- Authorization: OAuth oauth_consumer_key="hoge", oauth_nonce="foobar", ...
という ", " で区切って "" で括ったヘッダをつける方法もある。
このあたりを読むかぎり、どっちでもいいっぽい。
最後に、サンプルとして、status_update する場合の手順を...
http://twitter.com/statuses/update.(xml | json) にむけて POST します。
POST で送る内容は status=test とか。
そして、こんなヘッダをくっつけます。
- Autorization: OAuth oauth_nonce="NONCE", oauth_timestamp="TIME", oauth_consumer_key="CONSUMER_KEY", oauth_signature_method="HMAC-SHA1", oauth_version="1.0", oauth_token="ACCESS_TOKEN", oauth_signature="SIGNATURE"
ただし、シグネチャの生成には、status=test を含めてください。
うまく行けば、何かしら帰ってきます。
だめだったら、400 とか 401 が帰ってきます。
OAuth 対応の Twitter API ラッパーライブラリ?を作ってみた
作っちゃいました、はい。
まだまだ未熟なので、信頼性を求める人は使わないでください。
ただし、実装はそれなりに参考になると思います。どうぞ。
そして、僕が書いた非常に汚いコード。(Python)
とにかく動いてくればどうでもよかったので、変なことになってるところがいくつもあります。
まともに整理もしてないのでぐちゃぐちゃですが、少しぐらいは参考になると思うのでおいておきます。
consumer_key と consumer_secret があれば、一連の流れを体感できます。
(一応、サンプルとして適当に登録した Consumer Key を入れてあります)
(Access Token, Secert は、2回目以降に Access Token の取得に至るまでの過程をスキップしたいときのためにあります)
(すなわち、入力しなくても結構です)
ただし、これいろいろ問題あることが分かっているので、興味のある人は python-twoauth の oauth.py を見たほうがいいかも...
こっちは、TL を表示する為の XML 解析するやつです。
適当に自分で書いたので、かなり意味不明ですが。
はじめまして。
私も以前にOAuthを(主にTwitter用に)ちょっと調べてみたのですが、Twitterの場合はOAuth Core 1.0 Revision A準拠みたいなので、RequestToken取得時のパラメータとしてoauth_callbackにConsumer側の任意のURLを指定しておくことで、ユーザが[Allow]を押した後、PIN (oauth_verifier)付きで指定URLにリダイレクトしてくれます。
PINの手動入力を省略することが出来るので、PCを対象としたConsumerならこちらのほうがよさげですね。
※Twitter側の設定画面でApplication TypeをBrowserにして、Callback URLに適当なURL(ダミーでもよいみたいです)を入れておく必要があります。
http://d.hatena.ne.jp/furyu-tei/20090929/1254225568
http://d.hatena.ne.jp/furyu-tei/20091001/1254354352
http://d.hatena.ne.jp/furyu-tei/20091119/1258635078
あたりにシーケンス例やサンプルアプリとそのソース(GAE/Python用)を置いてあります。ご参考まで。
※私も適当に調べた物なので、誤り等あればご指摘いただければ幸いです。
コメント、ありがとうございます。
確かに、Web アプリケーションで使う為であれば、そんな感じでリダイレクトさせると、いいようですね。
ただ、僕は今回ふつうに使うデスクトップアプリケーション (いわゆる Twitter クライアント) で OAuth を使うことを想定してこれを書いたので、こんな感じになっちゃいました...
でもよく考えたら、Web 上から使う人がこれ見たら、へんな理解をしてしまう可能性があるのでよくないですね。
あとで修正しておきます。
DropboxのOAuthを通過するために拝見して、すごく参考になりました。ただ、ここにハマリましたというところがあるのでコメントします。
GET&http%3A%2F%2Ftwitter.com%2Foauth%2Frequest_token&oauth_consumer_key%3DCONSUMER_KEY%26oauth_nonce%3DNONCE%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3DTIME%26oauth_version%3D1.0
これが「GET&URL&OAuth」という形式だとは最後まで気づきませんでした。てっきり「GET&URL?クエリストリング」という形式だと勘違いしてました。
末筆ですが、有用な情報ありがとうございました。
すいません><
もっと解りやすくメールで頂けないでしょうか?
1、どこどこのサイトで000と言うのをインストール
2、000を000の000にコピペとか
出来たらで良いのでお願い致します。
まず、インストールとかコピペそういう問題じゃないですよね。
OAuth の仕組みについて書いるだけなので。
一番わかりやすいのは、OAuth の公式ドキュメントです。
もし、OAuth を使いたいだけだと言うのであれば、既存のライブラリを使ったらいいと思います。
今でも色褪せない素晴らしい記事をありがとうございます!とても参考になりました!