これは Twitter Advent Calendar 24日目の記事です。昨日はharetaさんの「whywaitaの金でピザの件」でした。
昨日の記事にて、僕のブログとしてここ*1を指定されてしまったため、技術的なことを話さなければいけなくなった。ので、Twitterと認可について話す。
はじめに
これはTwitterの認可、つまるところOAuth1.0およびOAuth1.0aの解説である。特に断りのない限り、OAuth1.0/1.0aのことを以下ではOAuthと呼ぶ*2。本稿は厳密にOAuthの仕様*3に沿った解説をしていないかもしれないが、実際に筆者がTwitter APIライブラリ*4を作成する過程で調べた情報を記述したものであり、内容については保証をする。誤字脱字、間違った解説がある場合は@masawadaまでどうぞ。
Twitterの認証と認可
もともとTwitterはBASIC認証を採用しており、認証にHTTPリクエストを用いることもできた。BASIC認証はパスワードが平文で流される、HTTPSにしてもユーザが悪意のあるクライアントアプリケーションにID/パスワードを渡す可能性がある、リクエストできるAPIを制限できない(全てのAPIエンドポイントについて認可される)等の問題を抱えており、2010年8月31日にBASIC認証を廃止しOAuthに移行することとなった。
なお、このときカウントダウンサイトとして使われていたドメインは絶対に失敗しない引越し土日マニュアルになっている*5。死んでくれ。
おことわり
Twitterで実装されるOAuth1.0/1.0aは一部ずさんな点があるため、PINベースの認可について解説する。現在は変わっているかもしれないが、筆者がTwitter APIライブラリを作った時点ではPINベースがもっとも確実とされていた。(参考: http://www.slideshare.net/nekoruri/20130301-twitter-oauthvulnerability)
Twitter OAuthの概要
CK/CSの取得
TwitterでOAuthを使用したアプリケーションを作成するには、Consumer KeyおよびConsumer Secret(以下CK/CS)を取得する必要がある。https://dev.twitter.comからTwitterアカウントでログインし、Appを作成、CK/CSを取得する。
OAuthなので、アプリケーションにどのAPIへのアクセスを認可するかを変更することができる。AppのページからPermissionを開いて、ラジオボタンで選択・保存する。
- Read only
- Read and Write
- Read, Write and Access direct messages
の三点になっており、上から順にアクセスできるAPIエンドポイントが増える。なお、どの権限でもユーザのパスワードを閲覧することはできない。
認可の流れ
以下の流れに沿ってアプリケーションに認可を与える。
- Authorize URIの取得
- Authorize
- Access Tokenの発行
Authorizationヘッダ
OAuthによる認可を必要とするAPIにリクエストを送る際、HTTPリクエストヘッダにAuthorizationヘッダを付加する必要がある。Authorizationヘッダは以下のparamsを含む。
param名 | 内容 |
---|---|
oauth_consumer_key | 取得したConsumer Key |
oauth_nonce | リクエスト毎にユニークな文字列(文字数はいくつでもよい) |
oauth_signature | 署名文字列(生成方法は後述) |
oauth_signature_method | "HMAC-SHA1" |
oauth_timestamp | リクエストの時間(UNIX Epoch) |
oauth_token | Access Token |
oauth_version | "1.0" |
ただし、OAuth系のエンドポイント(oauth/request_token
、oauth/access_token
等)は例外であり、一部のparamsを必要とせず、別のparamsを要求する。
oauth_signatureの生成
Twitter APIへの要求において、最も気を遣う部分のひとつがoauth_signatureの生成である。どのエンドポイントにおいてもこの生成方法は共通である。
- リクエストメソッド(GETまたはPOST, 大文字)とリクエスト先のURI
&
で繋ぐ- このとき、リクエスト先のURIはURIエンコードする。
- JavaScriptの場合encodeURIComponentでは不十分で、RFC 3986に準拠する必要がある。
- 参考: encodeURIComponent() - JavaScript | MDN
- oauth_signatureを除くoauth paramsをキーの辞書順にソートし、キーと値を
=
で繋ぐ- このとき、値はURIエンコードする。
- JavaScriptの場合1と同様にencodeURIComponentでは不十分で、RFC 3986に準拠する必要がある。
- 1で文字列と2で作った文字列を
&
で繋ぐ - HMACのSecret Keyを生成する。Consumer SecretとAccess Token Secretを
&
で繋ぐ- Access Token Secretが空の場合はConsumer Secretの最後に
&
を付加する
- Access Token Secretが空の場合はConsumer Secretの最後に
- 2で作った文字列をSHA-1でハッシュする
- 4で得られたハッシュを3で作ったSecret Keyを用いてHMACをとる
- HMACについてはWikipediaあたり見ると良い
- Hash-based message authentication code - Wikipedia
以上で得られた文字列がoauth_signatureとなる。これを最後にoauth paramsに加えてAuthorizationヘッダに付加する。
Authorize URIの取得
まずはユーザがアプリケーションに認可を与えるかどうかを決定できるページ(Authorizeページ)のURIを取得する。Authorizeページはhttps://api.twitter.com/oauth/authorize
またはhttps://api.twitter.com/oauth/authenticate
のいずれかであり(詳細は後述)、これにGETメソッドでoauth_tokenクエリを付加すると開くことができる。つまり、このoauth_tokenを取得する必要がある。
oauth_tokenを取得するには、oauth/request_token
にリクエストを送る。この時のoauth paramsは通常とは異なり、以下のparamsを要求する。
param名 | 内容 |
---|---|
oauth_callback | "oob" |
oauth_consumer_key | 取得したConsumer Key |
oauth_nonce | リクエスト毎にユニークな文字列(文字数はいくつでもよい) |
oauth_signature | 署名文字列(生成方法は後述) |
oauth_signature_method | "HMAC-SHA1" |
oauth_timestamp | リクエストの時間(UNIX Epoch) |
oauth_version | "1.0" |
また、signatureを生成する際に用いるAccess Token Secretは空なので、HMACのSecret KeyはConsumer Secretに&
を付加した文字列になる。
これらをAuthorizationヘッダに追加し、https://api.twitter.com/oauth/request_token
に対してPOSTリクエストを行うとoauth_token及びoauth_token_secretを得ることができる。これら2つは、OAuthで認可を得るまでアプリケーション側で保持しておく必要がある。
Authorize
PINベースのOAuthの場合、https://api.twitter.com/oauth/authorize
を用いる。https://api.twitter.com/oauth/authorize?oauth_token=
に続けて前項で得たoauth_tokenの文字列を付加したURIへユーザを誘導する。ユーザはこのページでTwitterにログインし、アプリケーションを認可するとPINコードを得ることができる。
Access Tokenの発行
最後に、Access TokenおよびAccess Token Secretを発行する。これを発行すると、以後認可を得た範囲で自由にAPIにリクエストを送ることができる。
Access Tokenを取得するには、oauth/access_token
にリクエストを送る。この時のoauth paramsは通常とは異なり、以下のparamsを要求する。
param名 | 内容 |
---|---|
oauth_consumer_key | 取得したConsumer Key |
oauth_nonce | リクエスト毎にユニークな文字列(文字数はいくつでもよい) |
oauth_signature | 署名文字列(生成方法は後述) |
oauth_signature_method | "HMAC-SHA1" |
oauth_timestamp | リクエストの時間(UNIX Epoch) |
oauth_verifier | 前項で得たPINコード |
oauth_version | "1.0" |
また、signatureを生成する際に用いるAccess Token Secretにはoauth/request_token
で取得したoauth_tokenを指定する。
これらをAuthorizationヘッダに追加し、https://api.twitter.com/oauth/access_token
に対してPOSTリクエストを行うとaccess_token及びaccess_token_secretを得ることができる。これでアプリケーションの認可が完了する。
oauth/authorizeとoauth/authenticateの違い
Twitterはユーザに踏ませるページとしてoauth/authorize
とoauth/authenticate
の二種類を用意している。前者はアプリケーションが認可済の場合でも毎回認可を行うかユーザに許可を得る。後者はアプリケーションが認可済の場合、なにもせずともアプリケーションへのリダイレクトを発生させる。特に理由がない限り、多少の利便性を残っても前者を用いた方がユーザとしては安心できる。
まとめ
というわけでざっと流れを説明することはできたと思う。基本的にはTwitter APIライブラリがこれらをカバーするため意識する必要はないが、内部でどう処理されているのかは理解しておくとライブラリのサポートが打ち切られる等なにか問題が発生した場合でも自分で書き換えるなどして対処することができるだろう。
明日はharetaさんの記事です。
*1:雑談用もある http://masawada.hatenadiary.com/
*2:OAuth2.0というバージョンもあり、Twitter APIにもエンドポイントが存在する
*3:RFC 5849 - The OAuth 1.0 Protocol
*4:GitHub - masawada/violet: A Twitter Library for Firefox OS
*5: