こんにちは、ritouです。
今回の内容は、Webブラウザからのみ利用できるサービスや特にiPhoneアプリのみ提供しているサービスではなく、
「一つのサービスをWebブラウザからもモバイルアプリからも利用できるようなサービス」についての話です。
こちらで取り上げられている内容です。
http://subtech.g.hatena.ne.jp/mala/20120214/1329199851
内容は
- OAuth 2.0でユーザーが認可をする"アプリケーション"とは何?
- ユーザー、認可サーバー、クライアントの3者で認識にずれがあるのでは?
- 認識の違いを解消するために認可サーバー、クライアントができることは?
という感じです。
OAuth 2.0でユーザーが認可をする"アプリケーション"とは何?
いろんな答えが返ってくると思われます。
- 「同意画面に書いてる内容によるんじゃないすか?」
- 「仕様見ると、clientってのはWebアプリケーションやモバイルのアプリのことなのでそれら単位」
- 「同じclient_id使ってWebアプリケーションからもモバイルアプリケーションからアクセストークンもらえる。つまりはサービス全体」
皆様はどう思われますでしょうか?
OAuth 2.0の仕様から確認しましょう。
OAuth 2.0の仕様ではサービス全体ではなく個別で登録しなければならない!
いつのまにかDraft 25です。
http://tools.ietf.org/html/draft-ietf-oauth-v2-25
response_type=code tokenとかあるので仕様曖昧だよな〜と思っていたのですが、普通に書いてありました。
A client application consisting of multiple components, each with its
own client type (e.g. a distributed client with both a confidential
server-based component and a public browser-based component), MUST
register each component separately as a different client to ensure
proper handling by the authorization server.
- Clientはユーザーに代わって保護リソースにアクセスするアプリケーション。
- Client Typesとして、秘密鍵を安全に管理できるconfidential、クライアントサイドで動いて管理できないのはpublic
- ConfidentialならAuthZ Code, PublicなのはImplicit使え
- サーバーサイドとクライアントサイドの両方のComponentから構成されている場合、別々で登録しろ!
ちなみにDaft 22ベースの翻訳版にはこの文章ありませんでした。
ということで、世の中の認可サーバーには
- client登録時にClient Typeが何かとか意識しない(SDK使ってモバイルの公式アプリと連携されたりしているとこはいろいろやってるところがある)
- 一つのclient_idでAuthZ Code/Implicitの両方を利用できる
というところもあるでしょう。
すると、
「同じclient_id使ってWebアプリケーションからもモバイルアプリケーションからアクセストークンもらえる。つまりはサービス全体で許可もらってる」
という実装が可能になります。
サービス全体だと思って作ってる人たちはたくさんいると思う
PCのWebブラウザでもモバイルアプリからも使えるようにしよう
↓
(A),(B)のAPIアクセスの処理はWebサーバーに集約するぜ
↓
モバイルアプリで取得したトークンもWebサーバーに送るぜ
↓
この設計は無駄がない!リリース!
という流れで実装されたサービスもあると思います。
エンドユーザー、認可サーバー、クライアントの3者間で認識のずれがあるのでは?
このようなつくりになっているクライアントがある場合に、認可サーバーとエンドユーザーの認識にずれがあるのではないかと思います。
- 認可サーバーは「サービス全体」にリソースアクセスを提供することを想定・許容しているのか?
- ユーザーは「サービス全体」にリソースアクセスを提供することに同意しているのか?
ずれをなくすために認可サーバー、クライアントができることは?
認可サーバー : クライアント単位で利用できるFlowの制限や同意画面の内容を精査
上記のとおり、OAuth 2.0の仕様ではサーバーサイドとクライアントサイドのアプリを別々に扱う必要があります。
Client単位の制御を厳密にやろうと思うと、こんな感じになると思います。
- Client登録時に、利用するresponse_type(Flow)を選択させる
- Authorization Endpointでclient_idとresponse_typeのチェック
あとは、アクセストークンを同じサービス内で使いまわされてしまっては同じことです。
「同一サービス内でもAccess Tokenをクライアントサイドからサーバサイドに流すな」というルールを開発者に同意させることも必要でしょう。
ユーザーへの配慮も必要です。
同意画面に「アプリケーション名 : ○○」と「アプリケーション名 : ○○ iPhone/iPad アプリ」と見せても、ユーザーはなんなのか理解できないかと思いますので、
というような表記にしてもよいかと思います。
クライアント : サーバーサイドとクライアントサイドでリソースアクセスの処理を分離
- サーバーサイド : PCブラウザにおいてリソースアクセスの許可をもらった場合のみ、APIアクセスを実行する。
- クライアントサイド : クライアントサイドでリソースアクセスの許可をもらい、APIアクセスを実行する。その結果のユーザー識別子などを用いてサーバサイドと連携する。
という感じでしょうか。
少し面倒に感じますが、広告でもリソースアクセスでもなんでも、ユーザーからもらった許可範囲を超えるようなことはしてはいけません。
PPID使うとなると連携できないのでは?などの話もあるかと思いますので、このあたりの処理内容についてもいろいろベストプラクティスを考えていければと思います。
ではまた。