OAuth 2.0でClientのデータをExternal Protected Resourceとして扱う方法

こんばんは、ritouです。
前回のエントリの続きで、OAuth 2.0でClientのデータに他のClientから安全にアクセスできる方法を考えました

何がやりたいか

まず、現状のOAuth 2.0でのServer,Clientの関係はこんな感じになりますねと。

twitpicのように、ClientがWeb Serverで動いていてそこのデータを操作できるAPIがあるとします。このAPIを他のTwitter Clientが利用しようと思った場合、OAuth Echoを使うところですが、bearer tokenの場合はちょっと考えなければいけません。

そこで、このtwitpicを"外部のリソースサーバ"ととらえ、AuthZの取得の部分から拡張して安全にアクセスできるようなしくみを考えてみましたと。


登場人物

上の説明にあるとおり、外部リソースサーバ兼実は普通のClientという立場を定義します。

Client as an External Resource Server

って感じですかね。長いのでCERSとでも呼んでおきましょうか。

現状のOAuth 2.0 最新Draftにおける拡張範囲

最新仕様はこちら。
draft-ietf-oauth-v2-16 - The OAuth 2.0 Authorization Framework

このうち、拡張する部分は以下の2か所です。

  • 4. Obtaining Authorization
  • 5. Issuing an Access Token
  • 7. Accessing Protected Resources

考えた仕様の内容

AuthZ取得要求

Authorization RequestのScopeパラメータに以下の値をセットします。

  • 1. CERSが事前にAuthZ Serverに対して登録しておいた、Scope文字列(例:twitpic)
  • 2. CERSのリソースを示すURL(例:http://api.twitpic.com/)
GET /authorize?response_type=code&client_id=s6BhdRkqt3&
redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb&scope=r_profile%20twitpic
HTTP/1.1
Host: server.example.com
GET /authorize?response_type=code&client_id=s6BhdRkqt3&
redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb&scope=r_profile%20http%3A%2F%2Fapi.twitpic.com%2F
HTTP/1.1
Host: server.example.com

AuthZ Serverは、受け取った値が登録されているかどうかをチェックします。
この登録もめんどいかもしれないので、AuthZ ServerがDiscoveryを行い、CERSのClient IDを返したらOKとかでも良いかもしれません。

AuthZ ServerはConsent Page(同意画面)でCERSのリソースにアクセスすることをユーザーに提示して、同意/許可をもらいます。

Access Token発行

OAuth Echoの課題として、bearer tokenを利用するケースがあります。
通常のResource Serverに送られるAccess Tokenと、CERSに送られるAccess TokenのScopeはそれぞれ自分たちが扱っているリソースの範囲内でなければなりません。

よって、AuthZ Serverは現状のAccess TokenのScopeにはCERS用のScopeは含まず、CERS用のAccess Tokenを追加で返します。

{
       "access_token":"SlAV32hkKG",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"8xLOxBtZp8",
       "cers_access_tokens": [
            {
                "scope": "twitpic",
                "access_token": "atokenstrfortwitpic",
                "token_type":"example",
                "expires_in": 3600,
                "refresh_token":"rtokenstrfortwitpic"
            }
        ]
}
{
       "access_token":"SlAV32hkKG",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"8xLOxBtZp8",
       "cers_access_tokens": [
            {
                "scope": "http://api.twitpic.com/",
                "access_token": "atoken2strfortwitpic",
                "token_type":"example",
                "expires_in": 3600,
                "refresh_token":"rtoken2strfortwitpic"
            }
        ]
}
リソースアクセス

Clientは、それぞれのAccess TokenをScopeの値に合わせて使い分けます。
しかし、CERSは受け取ったTokenの検証ができません。
CERSはAuthZ ServerのCERS専用Endpointにリクエストを送ります。

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=cers_token&client_id=cidstrfortwitpic&
access_token=atoken2strfortwitpic

AuthZ Serverは、レスポンスでEnd UserとClientのデータを返します。
項目はTBDですが、最低限、Client名とユーザー識別子ですね。

{
       "client_name":"Sample Client Name",
       "user_id":"enduseridentitystr",
       ...(TBD)...
}

CERSはこれらのデータを以下のように利用します。

  • user_id : ユーザーの特定
  • client_name : Client名の表示など

以上が、簡単に考えた仕様の概要です。

OAuth Echoと比較した結果

  • ユーザーの同意がもらえる
  • Clientはリソースアクセス時の処理が簡単になる
  • CERSはClientデータもAuthZ からもらえるので、別途Clientの登録/管理は不要

ここまで考えてみましたが、興味がある人はいるのでしょうか?
ではまた!