OAuth 2.0 の Response Type 全パターン
特に新しい話題ではないですが、定期的に質問されてる気がするので記事にしときます。
OAuth 2.0 の Core には、”code” と “token” という2つの response_type が定義されています。
それぞれ “Code Grant” と “Implicit Grant” と呼ばれることもありますし、歴史的経緯により “Code Flow” と “Implicit Flow” と呼ぶこともあります。
ほとんどのケースでは、この2つの response_type のどちらかを使っているかと思いますが、実はこれ以外にも以下の response_type のパターンが存在します。 (仕様はこちら)
- none
- code token
- id_token
- id_token code
- id_token token
- id_token code token
id_token ってのが含まれてるのは、OpenID Connect で利用する response_type なので、OAuth 2.0 だけを実装する場合は無視して OK です。
でもこんなにいっぱいあると、Server 側 (OP 側) もどこまで実装したらいいかわかんないし、Client 側 (RP 側) もどれ使うのが一番いいのかわかんないですよね。特に OpenID Connect 使う場合は。
そんなこんなで、「どれ実装したらいいの?」とか、「どれ使えばいいの?」っていう質問を、Server 側の人にも Client 側の人にも、半年に一回くらいされる気がします。
この機会に、それぞれの response_type で想定される Use-Case をまとめておきましょう。
none
「Approve はするけど、access_token (と id_token) は今はいらない」って時に使います。
はい、「それいつやねん」って思ったそこのあなた、あなたはきっとこれ使う事ないです。
世の中のごく一部には、これが必要な人もいるようですが、僕もいままで使ったことないです。
code token
Native App で access_token 使うんだけど、Native App の Backend Server 側でも access_token (と id_token) が欲しい時に使います。
fragment に code と access_token がついて返って来るので、access_token はそのまま Native App が内部に保持して、code だけを Native App から Backend Server に渡します。
Backend Server はその code を Token Endpoint に送って access_token (と id_token) を取得します。
もしかしたら Native App から access_token を Backend Server に送るような実装してる人もいるかもしれませんが、そうすると以下のようなデメリットがあります。
- Token Replace Attack に対して脆弱になりがち
- Backend Server でも refresh_token を取得できない
- Implicit Flow 経由で発行される access_token は lifetime が短くなりがち (Server 側の実装依存)
id_token
access_token が不要な時に使います。
Web App / Native App どちらでも使われうるかと思います。
ただしこれ使うと fragment に id_token ついて返ってくるので、Web App からは扱いづらいかもしれません。
「response_type=code 使って access_token 捨てればいいやん」って言われたら、「その通りですね」とお返しします。
また、Native App 側で id_token 使ってユーザー認証するケースって、そんなに多くはなさそうです。
この response_type は、あまり使う機会なさそうです。
id_token code
Native App で id_token 使うんだけど、Native App の Backend Server 側でも access_token (と id_token) が欲しい時に使います。
fragment に code と id_token ついて返ってくるので、id_token はそのまま Native App が内部に保持して、code だけを Native App から Backend Server に渡します。
Backend Server はその code を Token Endpoint に送って access_token (と id_token) を取得します。
ただこの response_type も、Native App 側で id_token が必要ってケースなんで、あまり使う機会なさそうです。
※ なぜか YConnect だけはこれを response_type=code 相当の response_type として利用しないといけないのですが、あれは YConnect の Bug です。
id_token token
Backend Server に code 渡す必要なくて、Native App 側だけで id_token と access_token 使えればそれで OK ってときに使います。
fragment に access_token と id_token ついて返ってきます。
この response_type も、Native App 側で id_token が必要ってケースなんで、あまり使う機会なさそうです。
id_token code token
Native App 側でも Backend Server 側でも id_token と access_token 両方必要な時に使います。
fragment に access_token と code と id_token ついて返ってくるので、access_token と id_token はそのまま Native App が内部に保持して、code だけを Native App から Backend Server に渡します。
Backend Server はその code を Token Endpoint に送って access_token (と id_token) を取得します。
この response_type も、Native App 側で id_token が必要ってケースなんで、あまり使う機会なさそうです。
まとめ
Server 側は、とりあえず以下の3つさえサポートしてれば、大抵の Use Case はサポートできそうです。
- code
- token
- code token
Client 側も、基本は以下のような基準で response_type 選べば良さそうです。
- Web App なら code
- Backend Server なしの Native App なら token
- Backend Server ありの Native App なら code token
補足
本記事全体として、Native App を JS App に置き換えても同様です。
また、広く公開される IdP を作る場合は、以下のようなケースも考慮しましょう。
Native App 側で id_token が必要なケース
Native App 側でマルチアカウント対応してるような場合は、Native App 側で id_token が必要になるケースはあるかもしれません。
そういう Client にも対応したい Server は、(none 以外) 全部サポートしましょう。
Native App 側で code を使うケース
Native App から Token Endpoint に code を送るケースもあります。
この場合は、Native App 側で refresh_token を取得したいケースが多いです。
access_token の lifetime が短く、Native App で頻繁に AuthZ Request を送りたくない場合などには、Native App でも refresh_token が必要になるのです。
ただしこの場合、Token Endpoint での Client Authentication を OPTIONAL にする必要があるので注意してください。