GoogleのCross-client Identityのしくみについて

こんばんは、ritouです。

GoogleのCross-client Identityっていうドキュメントについて気にされている方がいたので自分なりの解釈を書いておこうと思います。
GoogleのCross-client Identity - 高温処理済みコースケ

何の話か

これですね。
Cross-client Identity  |  Google Identity Platform  |  Google Developers
実はこのドキュメントけっこう前に出たやつなんですが、あまり注目してる人は少ないですね。

概要はこんな感じです。

  • 一般的には、1つのプロダクトにWebアプリやNativeアプリなど様々なコンポーネントのアプリがある
  • Googleはそのあたりを意識して"プロジェクト"の下にアプリケーションがぶら下がるようになっており、それぞれがclient_idを持ってる
  • 普通のOAuthではアプリケーション毎にscopeをつけてリソースアクセスへの許可をもらう
  • Googleはどれか一つのアプリケーションで認可を得たら、ユーザーはプロジェクト全体を信用すると考える
  • ユーザーが認証済で、同一プロジェクトの異なるアプリケーションで同じscopeの認可要求が送られたときは認可画面を出さない(省略する)ようにする

という感じです。

マルチコンポーネントなClientへの認可については、むかーしこんな記事を書きました。
OAuth 2.0でユーザーが認可をする"アプリケーション"とはサービス全体のことではない - r-weblife
Googleの場合はそれぞれのコンポーネント単位でclient_idを分けて利用できる認可フローを制限しつつ、バックエンドで連携させる方法を提供しているという感じです。

上記エントリのとおり、仕様ではそれぞれのアプリケーションについての認可であり、プロジェクト単位じゃないよねーなんて思ったりしますが、一番重要なのはユーザーが「騙された!」って思わないかどうかなのでGoogleがそのあたりの説明を頑張るのであれば文句は言いません。
(と言いつつもGoogleFacebookもOAuthの認可画面はどんどんあっさりしていって細かく説明できている気はあまりしないです)

具体的に何をする方法が書いてあるか

上記の実現のため、3つの方法が書いてあります。
デモまでやりたいところですが、Androidアプリの開発が必要になるのでGoogleの提供してるサンプルを見ればよいと思います。
https://github.com/googledrive/crossclientoauth2-android

Cross-client access tokens

例えばWebとAndroidで認可要求で指定されるscopeが同じとき、どちらかで先に認可されていたらもう片方の認可画面はskipされるっていう話です。

Android ID tokens

AndroidアプリからWebアプリ向けのID Tokenを取得できて、バックエンドサーバーとの連携(利用ユーザーの特定)に使えるっていう話です。
Android側でscopeを"audience:server:client_id:" + client_idにしてgetTokenを呼ぶととれると。

String scope = "audience:server:client_id:" + CLIENT_ID;
String idToken = GoogleAuthUtil.getToken(context, accountName, scope);

プロジェクトに対して認可されてないときとか、そもそもユーザー認証がされてないときにどうなるかはわからないですね。エラーが返るのかもです。
で、取得できるID TokenのPayloadは

  • iss : Googleが作成したID Tokenなのでaccounts.google.comになる
  • aud : Webアプリのclient_id
  • azp : Androidアプリのclient_id
  • email : ユーザーのメールアドレス

を含みます。とあります。

このID TokenはAndroidアプリからHTTPSでWebアプリに送られます。
Webアプリは次のように検証します。

  • 署名の検証
  • audが自らのものであることを確認

その上で、emailの値でユーザーを識別するとありますが、ここはemailじゃなくてsubじゃないのかなと疑問が残ります。これも検証が必要ですね。
Androidアプリ-Webアプリ間のID Token置換の可能性も考慮すると、azp, exp, iat, nonceなど細かい検証までやるのが良いですね。
いろいろドキュメントに書いてないので対応してるのか気になるところです。

Android app obtains offline access for web back-end

AndroidアプリからWebアプリ向けのAuthorization Codeが取得できて、バックエンドに送ればWebアプリはAccess Tokenとれるっていう話です。
ネイティブアプリからのOAuth 2.0の話をするときに、私は「クライアント側ではAuthrization Codeもらって、それをバックエンドのWebサーバーに送ってそっちでやれ派」の立場をとっていましたが、それと同じ感じです。

ここもscopeの値に特別な値を指定する必要があります。

String scope = String.format("oauth2:server:client_id:%s:api_scope:%s", CLIENT_ID, TextUtils.join(" ", SCOPES));
String exchangeCode = GoogleAuthUtil.getToken(context, accountName, scope);

その他、バックエンドのWebアプリが行うことが細かく書いてあります。

気になること

Googleのやりたいことはわかりますが、こまけぇことを気にするユーザーにとっては迷惑に感じることもあるかもしれません。
Webアプリ側でOAuthの認可処理をしていたおかげで、モバイルアプリを利用し始めたときに"想定外にシームレスに"Googleのプロフィール情報が表示されたりすることか。

便利になるのは良いことですが、ユーザーの想定外のことが起こってしまうと"騙された"、"なんか怖い"といった印象を与えてしまいかねません。
これらの機能を利用する場合はユーザーへの説明を用意するなど少しだけ配慮をお願いしたいところです。



あと、このようなネタフリは歓迎ですので何かありましたら @ritou へのメンション付きで発言してください。
ではまた!