いろいろと話題のOAuthですが、その意義とか仕組みとかはさておき、実際に実装してみようと思ったときに、ややこしいのはsignatureを作ってリクエストを生成するところなので、そのあたりをざっとメモっておきます。
あくまで個人的な覚書なんで、より詳しくは本家のサイトを参照してください。OAuth Core 1.0a
以下、NSString を ‘&’ や ‘=’ で連結しているかのような記述がありますが、単なる文字連結のイメージですのでご了承下さい。
はじめに
全体を通していえることですが、すべてのGET/POSTパラメータは key, value ともにURLエンコードされている必要があります。(実際 key のほうは不要であることが多いですが)
OAuthでのURLエンコードはRFC3986準拠ですので注意しましょう。CFURLを用いて例えばこんなふうにできます。
CFStringRef encoded = CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(CFStringRef)str,
nil,
CFSTR(":/?=,!$&'()*+;[]@#"),
kCFStringEncodingUTF8);
以下、http://twitter.com/statuses/user_timeline.xml?screen_name=itok_twit にアクセスすることを前提にメモっておきます。
標準パラメータ
OAuthの標準パラメータとして、以下のようなものがあります。(GETなりPOSTなりで渡す必要があります)
- oauth_consumer_key
-
twitterでアプリを登録したときにもらえる値。そのまま使います
- oauth_nonce
-
ユニークな文字列を作成。タイムスタンプでもよいけれど、より確実にUUIDを使うとか
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef nonce = CFUUIDCreateString(kCFAllocatorDefault, uuid);
CFRelease(uuid)
- oauth_signature_method
-
twitter は HMAC-SHA1 固定
- oauth_timestamp
-
タイムスタンプ。 time(NULL); の返り値でOK
- oauth_version
- 1.0固定
signature
signature の元となる signature base は分解した link や normalized parameter を元に ‘&’ で結合します。
NSString* base = [HTTP method]&[my_urlencode_rfc3986(link)]
&[my_urlencode_rfc3986(parameter)];
ここで link はいわゆる query をのぞいた部分。
NSString* link = @"http://twitter.com/statuses/user_timeline.xml";
normalized parameter は POST/GETパラメータ(標準パラメータ含む)を全部key=valueの形にして昇順ソートし、それを ‘&’ で結合して1つの文字列にしたものです。
NSString* parameter = [key1]=[val1]&...;
/* oauth_consumer_key=xxxx&oauth_nonce=xxxx&
oauth_signature_method=HMAC-SHA1&oauth_timestamp=123456&
oauth_version=1.0&screen_name=itok_twit */
次に HMAC で使う key も ‘&’ で結合。
NSString* hmacKey = [my_urlencode_rfc3986(consumer secret)]
&[my_urlencode_rfc3986(token secret) *なければ空文字];
signature base と HMAC key から HMAC-SHA1 ハッシュを生成し、これを Base64 エンコーディングしてURLエンコードして signature とします。
NSString* digest = my_hmac_sha1(base, hmacKey);
NSString* base64 = my_base64_encode(digest);
NSString* signature = my_urlencode_rfc3986(base64);
パラメータに oauth_signature=signature を追加して、最終的にアクセスするURLの出来上がり。
備考
- POSTは ContentType: application/x-www-form-urlencoded で行う
- より詳しい例は本家の Appendix 参照
と、ざーっと書き連ねてみました。手元で動いている現状のソースから引っ張ってきたので多分大丈夫と思いますが、なんかおかしかったら教えてください(いつでも弱気)