Hello OAuth 2.0, Good-bye OAuth 1.0!

Author: Nov Matake
Date:

おっす、おらOAuthおにーさん!

ついにOAuth 2.0 CoreとBearerがそれぞれRFCに!!!

RFC 6749 - The OAuth 2.0 Authorization Framework

RFC 6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage

このブログができたころには既にOAuth 2.0のdraftが出てたのですが、そういえばOAuth.jpっていつできたんだっけ?と思ってみて見ると…

OAuth.jpを立ち上げました。 - OAuth.jp

2010年7月!

そんな長い間やってたのか。。

FB Graph APIが出たのが2010年4月なので、OAuth 2.0の実装がでてからかれこれ2年半ほどでようやくRFCになった訳ですね。

さて、RFC化された直後の国内の反応ですが..

そうなんです。OAuth 2.0 Coreには、こう書いてあるんですね。

This specification replaces and obsoletes the OAuth 1.0 protocol described in RFC 5849.

OAuth 1.0サポートしてるTwitter APIとかOpenSocial採用してるプラットフォーム各社とか、どうなるんでしょうね?

そういえばそれ以外にも @ritou がまたブログ記事書いてましたね。

RFCになったOAuth 2.0を使ってGoogleはどれだけパスワード入力を減らせるのか - r-weblife

OAuthおねーさんの次回作が気になるところです。

OAuthのoffline_accessについて

Author: Nov Matake
Date:

少し前ですが、OpenID Connectのbitbuckeetでoffline_accessについての議論がされていたので、まとめておきます。

Googleの場合

offline access の定義

  • refresh tokenが発行されるのがoffline。
  • 特にoffline accessを要求しない限り、デフォルトではonline accessを要求したものと見なされる。
  • online accessの場合はrefresh tokenは発行されない。
  • refresh tokenはユーザーがrevokeするまで有効。

auto approval

  • 一度ApproveされたClientに対しては、accessがrevokeされるまでは次回以降のAuthorization Request時の同意画面はスキップされる。
  • 同意画面がスキップされる場合、refresh tokenは発行されない。

promptとaccess_type

  • Authorization Request時にprompt=trueというパラメーターを指定すると、auto approvalを無効化し、ユーザーに同意画面を見せることができる。
  • 同様にaccess_type=offlineを指定すると、offline accessを要求できる。
  • access_type=offlineを指定した場合、初回同意時にのみrefresh tokenが発行される。
  • それ以降もrefresh tokenが必要な場合は、prompt=trueとaccess_type=offlineを同時に指定すること。

AOLの場合

offline accessの定義

  • デフォルトではcode flowでは常にrefresh tokenが返される。
  • refresh tokenはユーザーがログアウトするまで有効。
  • ユーザーがログアウトしても有効なrefresh tokenが欲しい場合は、scopeにoffline_accessを指定する。

auto approval

  • ユーザーが明示的にチェックボックスにチェックを入れた場合のみ、次回以降の同意画面がスキップされる。
  • 同意画面がスキップされるケースでも、offline_accessを要求することができる。

ところでこのIssue、まだopenですね。

WebSocketでOAuth 2.0を使ってみた

Author: Nov Matake
Date:

WebSocket Serverでユーザー認証とか、WebSocket Serverの裏にRailsなりのAPIがあってNode.jsからそのAPI叩く見たいなのはそれなりにありそうなのに、あんまサンプルコード的なものが見当たらなかったので、自分で書いてみたのをここに公開することにします。

ClientがWebSocket Serverにつなぐ時、http://socket.example.com/?access_token=*** みたいなURLにアクセスして、ServerはそのToken元にユーザーを認証して、その後socketがつながってる間はNode.jsがそのtoken使って裏のRails APIにアクセスする、という使い方をしてます。

Access Tokenの保存先にMySQL使ってるのはあくまでRails側でそっちのが手っ取り早かったからで、ここはRedisでもMongoDBでもなんでもいいです。この例ではNode.js側ではAccess Tokenに紐づいたClientとかScopeとかを検証してないし。

https://gist.github.com/3300227

ところで、WebSocketではCookieベースの認証方式が主流なんですかね?

Re: OAuth 2.0のclient_secretって本当に秘密鍵ですか?

Author: Nov Matake
Date:

昨日こんな記事を見かけたので、記事にまとめることにします。

OAuth2.0のclient_secretって本当に秘密鍵ですか?

元記事にあるとおり、現状Native AppでのOAuth 2.0の実装は、API提供者・利用者ともにポリシーがバラバラで、混乱の元になっていると思います。

Googleのドキュメントにも「the client_secret is obviously not treated as a secret.」とあるわけだけど、そのくせclient_secretを使ってるし、ネットで調べても少なくない数の人がアプリに埋め込んでるので、client_secretを公開したときの問題を考えてみる。

“offline” アクセスと “online” アクセス

Googleは、“offline access” に対して以下のようなポリシーを持っています。

Upcoming changes to OAuth 2.0 endpoint - Google Apps Developer Blog

openid / connect / issues / #539 - Messages - 0. Add scope for offline access - Bitbucket

上の記事では議論が長くてかつ英語なので、簡単に要約すると、

  • access tokenが無効化されると、clientは新しいaccess tokenを取得しなければならない。
  • 新しいaccess tokenを受け取るには、ユーザーがその場にいる必要がある。ユーザーが既にclientのアクセスに同意している場合は、同意画面をスキップさせることができるので、ユーザーが毎回Googleの同意画面を見る必要は無い。
  • JS Appなど、ブラウザ内で動作していて常にユーザーとインタラクションしているclientは、同意画面さえスキップできればリダイレクトベースで必要に応じて毎回access tokenを取得すればよい。
  • スマホ上のNative Appの場合は、UX的に毎回ブラウザ経由してaccess tokenを取得するのはつらいので、ユーザーから明示的に “offline” アクセスへの同意を得て、次回以降はrefresh tokenを使って新しいaccess tokenを取得すればよい。

そして、Googleは、refresh tokenを伴う場合を “offline” アクセス、伴わない場合を “online” と定義しています。詳細は異なるものの、似たような定義はFacebookやAOLなども行っています。

Native Appに埋め込まれたclient_secretは簡単に漏洩する

このご時世 Charles などを使えば、自分のデバイス上で行われているSSLリクエストなら簡単に覗き見ることができます。

OAuth 2.0では、authorization codeとaccess tokenを交換する時とrefresh tokenをaccess tokenと交換する時に、client_secretを平文でAuthorization Server (この場合はGoogle) に送信します。

そのため、上記2つのいずれかのリクエストがiPhone上のNative Appから発行されるなら、Jailbreakや逆コンパイルなどせずともエンドユーザーなら誰でも、そのアプリに埋め込まれたclient_secretを知ることができます。

OAuth 2.0のclient_secretをアプリに埋め込んで配布するというのは、client_secretが漏洩する前提でそれを扱っているということです。そしてその場合、当然以下のような疑問がでてきます。

client_secretが漏洩してはいけないのか?

これに関しては、例えばFacebook Graph APIの場合であれば、client_secretが漏洩すると以下のようなリスクがあります。(個人的にGoogle APIは使ってないので、Googleに関しては僕はよく把握していません)

client_secretが漏洩した場合のリスクはAPI提供者側のポリシーに依存するため、Generalな解答をするとすれば以下のようになるでしょう。(ちなみに、いまClient Credentials Flowがサポートされていないからといって、将来にわたってその状態が維持される保証があるわけではないです。その場合はclient_secretを発行しなおしたりするんでしょうかね? > だれとなく)

全てのAPI提供者がNative Appに埋め込まれたclient_secretが漏洩することを前提としたアクセスコントロールを実施しているわけでも無いようですし、そもそもNative Appにclient_secretを埋め込むことを禁止しているFacebookのようなOAuth Serverも存在する (=> 本来こっちの方が一般的であるべき) ので、Developerにとっては混乱の元でしょうね。

Native Appにclient_secretを埋め込む前提で、その漏洩の可能性という点で見れば、OAuth 1.0を使った方が良い場合もあるでしょう。OAuth 1.0では、Native Appにclient_secretを埋め込んでもそれは署名計算に使われるだけで直接OAuth Serverに送信されることはありません。かといっていまからOAuth 1.0を採用するというのは、時代の流れ的にどうなんだということもありますが。

GoogleとFacebookのスタンスの違い

GoogleがNative App (= Installed Application) 用のフローを用意してNative Appにclient_secretを埋め込むように案内する一方、Native AppにはFB Official Appと連携したフローを用意してclient_secretを不要にしているFacebookの存在は、対照的です。

Googleの場合は、Client登録時にClientがWeb AppなのかNative Appなのかといった分類をさせているはずで、そのclient typeによってclient_secretを使ってできることに差を付けているのかもしれません。(要確認: Google APIよく知らないので、この辺詳しい人いたら教えてほしい)

Facebookの場合は、Native AppとWeb App、Facebook iFrame Appといった複数の種類のClientを、提供者が同一であれば同じclient_id (& client_secret) を使い回せるようにして、cross-platformな環境でアプリを提供しやすくしているため、client typeによってclient_secretの価値を変えるということはやりづらいのかも知れません。(じゃあGoogleはcross-platformなClientに対してどう考えてるの?ってのは、Googlerに直接聞いてみたいかも)

client_secretが漏洩した時に被害を受けるのは誰?

これもまた各OAuth ServerがどんなAPIを提供していて、OAuth 2.0のClient Credentials Flowを使って得たaccess tokenで何ができるのかに依存するので、一概には言えないのですが、よくあるケースとしてはAPI利用状況のAnalytics情報を取得したりするAPIが考えられるので、被害を受けるのはエンドユーザーというよりはClient Developer自身であることの方が多いでしょう。

client_secretを埋め込む実装をしているOAuth Client Developerは、一度利用しているAPIがClient Credentials Flowをサポートしているのか、Client Credentials Flowで得たaccess tokenでは何ができるのか、一度APIドキュメントを確認したりAPI提供者に問い合わせてみた方が良いかも知れません。

Facebookの用にclient_secretさえあれば任意のユーザーをBanできてしまったりする場合は、client_secretが漏洩することでClient Developerとエンドユーザー両方が被害を受けることもありえます。

蛇足: オレはこう思う!(だっけ?)

まぁこの辺りはOAuth 1.0からOAuth 2.0になってServer / Client双方にいろいろ選択肢が増えたので、各社バラバラな仕様になってしまって

When compared with OAuth 1.0, the 2.0 specification is more complex, less interoperable, less useful, more incomplete, and most importantly, less secure.

OAuth 2.0 and the Road to Hell

っていう前OAuth 2.0 Authorの彼の意見も、あながち無視できないところではある。