🙄

キミの認可O Auth2.0じゃないねぇ...― OIDCの属性情報で認可してもOAuth2.0の認可になってない?―

に公開
2

よくある勘違い

ついにOIDCのフローを理解し、実装完了...!
OIDCはOAuth 2.0を認証に使用できるように拡張したもの

つまり、

  1. OIDCで受け取ったアクセストークンを検証
  2. 検証OKならアクセストークンでUserInfoエンドポイントからユーザー情報を取得
  3. ユーザー情報をもとにロールベースの認可

これでOAuth 2.0準拠の完璧なシステムが完成している...! ふつくしい...!!

こんなことになってませんか?(筆者はなってました)
「OIDCはOAuth 2.0を認証に使用できるように拡張したもの」
これは正しいのですが、受け取ったアクセストークンで UserInfo の属性だけを見て機能可否を決めても、それはあなたのアプリの独自の認可であり、OAuth 2.0の認可にはなっていません。

用語を整理しながら、詳細を解説します

用語の整理

OAuth 2.0

  • 認可プロトコル
  • 超ざっくりいうと、OAuth 2.0 は、リソースオーナーの同意に基づき、認可サーバーがアクセストークンを発行し、リソースサーバーがそれを検証・強制することで、クライアントに保護リソースへの限定的アクセスを委任するための枠組み

フロー概要

https://tex2e.github.io/rfc-translater/html/rfc6749.html
から引用

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+
     
     Figure 1: Abstract Protocol Flow

図1に示されている抽象的なOAuth 2.0フローは、4つの役割間の相互作用を説明しており、以下のステップが含まれています。

(A)クライアントはリソース所有者に認可を要求します。許可要求は、リソース所有者に直接(図に示すように)行うことができますが、仲介サーバーとして許可サーバーを介して間接的に行うこともできます。

(B)クライアントは、この仕様で定義されている4つの許可タイプの1つを使用して、または拡張許可タイプを使用して表される、リソース所有者の許可を表す資格情報である許可許可を受け取ります。許可付与タイプは、クライアントが許可を要求するために使用する方法と、許可サーバーがサポートするタイプによって異なります。

(C)クライアントは、許可サーバーで認証し、許可付与を提示することにより、アクセストークンを要求します。

(D)認可サーバーはクライアントを認証し、認可付与を検証し、有効な場合はアクセストークンを発行します。

(E)クライアントは保護されたリソースをリソースサーバーに要求し、アクセストークンを提示して認証します。

(F)リソースサーバーはアクセストークンを検証し、有効な場合はリクエストを処理します

プロトコル概要

  • 認証プロトコル
  • OAuth2.0をベースに作られている
  • 認証成功すると、OpenID Providerが、Relaying Partyに対して、エンドユーザーの属性情報を提供する仕組み

OIDCのプロトコルの概要は以下です

OpenID Connect プロトコルは, おおまかに言って以下のステップに従う.

  1. RP (Client) が OpenID Provider (OP) にリクエストを送る.
  2. OP は End-User を認証し, 認可を受ける.
  3. OP は ID Token および (通常は) Access Token を返す.
  4. RP は Access Token を添えて UserInfo Endpoint にリクエストを送る.
  5. UserInfo Endpoint は End-User の Claim を返す.

これら一連のステップを以下に図示する.

+--------+                                   +--------+
|        |                                   |        |
|        |---------(1) AuthN Request-------->|        |
|        |                                   |        |
|        |  +--------+                       |        |
|        |  |        |                       |        |
|        |  |  End-  |<--(2) AuthN & AuthZ-->|        |
|        |  |  User  |                       |        |
|   RP   |  |        |                       |   OP   |
|        |  +--------+                       |        |
|        |                                   |        |
|        |<--------(3) AuthN Response--------|        |
|        |                                   |        |
|        |---------(4) UserInfo Request----->|        |
|        |                                   |        |
|        |<--------(5) UserInfo Response-----|        |
|        |                                   |        |
+--------+                                   +--------+

https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html
から引用

ザックリ解説

Q. 何がOAuth 2.0になってないのか?

A. 大きく分けて2点

  1. OIDCのUserInfoエンドポイントから得られた属性情報に基づいて認可しているだけで、あなたの欲しい情報そのものの(ユーザー情報以外)、リソース所有者、または認可サーバに許可を要求しているわけでない
  2. OAuth 2.0におけるリソースサーバーがアクセストークンを検証していない

詳細な解説

結局のところ、OIDCで発行されるアクセストークンでUserInfoから取得した属性情報で認可しても、それはOAuth 2.0ではないということです

また、OIDCで発行されるアクセストークンでは、対象となるリソースサーバーが決まっていることが多く、「自分が取得したい情報があるリソースサーバ」が対象になっているか確認する必要があります

そもそもOIDCがOAuth 2.0の拡張ってどういうことだっけ?

これは、大まかに以下2点に対して言っていると思われます

  1. トークン取得までのフローが一緒
    • OIDCがOAuth 2.0のフローをそのまま採用した形
  2. OAuth 2.0とは違い、IDトークンも発行するようにした

以下のYoutubeの動画がわかりやすいです

OAuth 2.0とOIDCの共通点を説明する図のスクリーンショット

引用: https://www.youtube.com/watch?v=PKPj_MmLq5E&t=1550s
(引用した動画はOAuth & OIDCがスーパー分かりやすい神動画です。詳しくはこの動画を見てください)

勘違いの要因 ―OIDCとOAuth 2.0のアクセストークン―

このような勘違いが起きる要因はOIDCとOAuth 2.0両方で「アクセストークン」という同じ名前のトークンが払い出されることではないでしょうか?

正確に言うと、OIDCで払い出されたアクセストークンが、必ずしもあなたのリソースサーバーに対するアクセストークンではないということです(IdPによってはあなたのリソースサーバーに対するOAuth2.0に準拠したアクセストークンになっていることがあります)。ユーザーの属性情報をユーザー情報が存在しているリソースサーバーから取得するという意味でOAuth 2.0のアクセストークンになっているのです

そして、OAuth 2.0に基づいたアクセストークンで認可するなら、ユーザーの属性情報は取得せずに認可でき、ユーザー情報に依存した認可はそのアプリの独自認可ということです

まとめ

  • OIDCはOAuth 2.0の拡張だが、「認証プロトコル」として拡張しただけ
  • OIDCで払い出されるアクセストークンはユーザー情報があるリソースサーバへのアクセストークンであり、あなたのシステムがアクセスするリソースサーバのアクセストークンとは限らない(scope等 次第)
  • UserInfoで属性を見て認可するのはアプリ固有の認可であって、OAuth 2.0準拠の認可ではない

おわりに

OIDCとOAuth 2.0むずすぎッ!

Discussion

ritouritou

認可の方向というか「誰が」「誰に」「何の権限を与える」ことを実現する仕組みなのか、OIDC/OAuthを使うことでそれをどの部分に適用できるのかを明確に意識することでより読みやすくなりそうだなと感じました。

OAuthは「認可サーバーが」「クライアントに対して」「リソースサーバーが保持するリソースオーナーの情報へのアクセスを許可する」仕組みです。
OIDCは「OpenID Providerが」「Relying Partyに対して」「エンドユーザーの属性情報を提供する」仕組みです。

これをどの範囲に適用するかというところで

  • Googleなんとかが例に出される「認可サーバー」「リソースサーバー」と「クライアント」が別サービスの3rd Partyパターン。リソースアクセスで受け取った情報やユーザー情報をクライアントがどう活用するかはある意味「自由」。
  • 同一サービス内で「認可サーバー」の立ち位置にあるID管理システムと「リソースサーバー」の立ち位置にあるサービスバックエンド、「クライアント」の立ち位置としてリソースアクセスを行うフロントエンドとかのアプリケーションといった1st Partyパターン

の2種類に分けられます。

この観点からこの記事を見ていくと、

受け取ったアクセストークンで UserInfo の属性だけを見て機能可否を決めても、あなたが用意している、ユーザー情報以外ののリソースサーバにおける OAuth 2.0 の「認可」にはなりません。

OAuthを1st Partyパターンに当てはめることを想定しているように見える中で、OIDCの3rd Partyパターンの導入では不十分(不適切?)、という主張にできます。初学者の読者は特にこの適用パターンについて混乱することが多いので、前提条件などを解説する際に参考にしてもらえたらと思います。

AtaroAtaro

コメントありがとうございます!

OIDCに明るそうな方からコメントいただいて嬉しいです(会社で推薦されたOAuth屋さんの書籍のReviewerをしていた方だったとは...)。

3rd Partyや1st Partyパターンといったパターンがあるのですね。勉強になりました。

おっしゃる通り、この記事で言いたかったことは

  1. 3rd Partyパターンで入手したユーザー情報に基づく認可はOAuth 2.0になっていない
  2. そのうえで上記の1.のパターンで認可を行うことを1st Partyパターンと混同してOAuth 2.0で認可できていると勘違いしやすいので注意が必要

ということになります

改定前の記事が分かりにくかった原因になりますが

  1. そもそもOIDCで発行されるアクセストークンは対象となるリソースサーバーが決まっている場合が多いが、「自分の所有するリソースサーバー」が指定されてないことも多いよね
  2. その場合、OAuth 2.0は他の代替手段で行うか、そもそも不可能だよね

という主張もしたかったのですが、うまく書けなかったからだと思います

記事を改訂しました