一瞬popup + 以降iframeでproxyするようなもの。XHR level2いらないのでやや動作環境が広がる。
- クライアント側ボタンクリックで window.open + ランダムなid(これをclient_id相当にする)の名前をつけてiframe埋め込み
- popup windowにiframeの名前をpostMessageで送る
- サーバー側: popup windowはiframeに対してpostMessageで返信(event.source.frames.xxxx)、api-domainのoriginであることを確認、cookieで認証してランダムなidとセットで使えるトークン発行
- トークン保存はmemcachedなど揮発性のストレージで良い。使っている限り期限が延長される。最長期限があってもよい(あったほうがよい)
- ログアウトとセットで破棄されるようになっていると良い
- iframeはポップアップwindowからメッセージを受け取る。ランダムなid + トークンを使ってAPIにアクセスする。
- iframeは親windowからメッセージを受け取る。あとはpostMessageでproxyしてXHRのリクエスト、レスポンスをやり取りする。
- iframeは親windowからのメッセージであることをevent.originを使って検証する
- トークンは親windowに渡ってはいけない。レスポンスだけ受け渡す。
図: http://cache.gyazo.com/feef74a84d49644470eba6cb7cb4aac5.png
iframe api-domain/proxy#client_id
popup auth-domain/authorize
popup windowは現状のブラウザの仕様上、ユーザー操作を起因にして開かないとまずブロックされる。ボタンやリンクを押す必要はあり。
親window自体が別サイトからpopup windowとして開かれて、ユーザーが操作して認可を与えた場合に、popup.frames[num].postMessageを使ってapi-domainにリクエストが送られてしまうと困る、api-domainは親windowからのmessageかどうかを検証する必要がある。
api-domainのoriginに不適切なページがあった場合に、例えばpostMessageで受け取ったデータを外部に漏らしちゃう、というようなものがあれば(XSSがある前提だとそもそも安全じゃないことになるが、こういったものだと単体ではクリティカルな脆弱性にならないはずのところ) tokenが外部に漏れてしまうことになる。何らかの方法でiframeがproxy用のURLであることの保証が出来ると良い。popup -> iframeはいきなりtokenを渡すのではなく、お互いにclient_idを知っているかどうかを確認してから渡す方が良いかも知れない。
XHR level2で直接リクエストしてレスポンスを受け取っているのか、postMessageを使ってiframe経由でリクエストしているのか、というのはライブラリレベルでは完全に隠蔽できるので、開発者は気にする必要がない。
これ、大前提としてこのAPI認可形式のプロトコル化(+JSライブラリの提供)を目指している、ということでいいのかな?
で、その上でコメントなんだけど
AuthzのドメインはCookie食ってるだろうし、トークンで識別する限りCookie必要ないだろうからAPIとは分けたほうがいいんじゃないのかなー。特に、ドメイン同じであることを前提としてしまうと、今現在そうなっていないAPIサービス(結構あるよね)にとっては本方式の採用にちょっと負荷がかかるかも。
api origin にproxy以外のページがあるケース、というのが、正直ほんとにあり得るのか良くわからないし、そこは実装者に対して「そんなページ作るな」じゃだめなのかな? apiドメインにjson/xml以外返すサービス入ってくることってどれくらいあるだろう? IEでHTMLとして解釈されちゃう脆弱性とかまだ影響するんだっけ?
あと
この項目の言わんとすることがまだよくわかってないかもしれないけど、親ウィンドウには外部スクリプト(悪さする可能性がある)が混入する可能性があるとした時、その場合でもスクリプトからtokenにアクセスできないようにしたい、要は何が何でも親ウインドウはtokenを見ることはできない、って状況を達成したい、ということでいいのかな?
これに対しては、先に書いたとおりapiドメインにproxy以外のページ置くな、が一番しっくりくるのだけど、そういう状況って(apiドメインにページが作られる状況)あるだろうか?