mokajima.com

OAuth 2.0 について学習したので頭の中を整理する

はじめに

「OAuth について学びたい!」と思い、ここ1週間学習していました。頭の中を整理するために、以下の2つについてまとめたいと思います。

  • OAuth 2.0 の概要
  • 認可コードグラントでクライアントがアクセストークンを取得するまでのフロー

なお、OAuth 2.0 について学習するまで、私の OAuth に対するイメージは「認証周りの話…🤔???」という程度でした。

OAuth 2.0 とは

OAuth 2.0 の標準仕様である RFC 6769 の Abstract では、OAuth 2.0 を次のように説明しています。

The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service,

和訳すると「OAuth 2.0 は, サードパーティーアプリケーションによるHTTPサービスへの限定的なアクセスを可能にする認可フレームワークである.」1 となります。

サードパーティーアプリケーション

サードパーティーアプリケーションとは、HTTP サービスの提供者以外が作成したアプリケーションのことです。

HTTP サービス

HTTP サービスとは、HTTP 経由で提供するサービスのことです。

限定的なアクセスを可能にする

限定的なアクセスを可能にするとは、HTTP サービスがホストする保護されたリソースへのアクセス権をサードパーティーアプリケーションに付与することを意味します。全権限ではないため、限定的となっています。

認可フレームワーク

認可とは、HTTP サービスのユーザーが、HTTP サービスがホストする保護されたリソースについて、サードパーティーアプリケーションのアクセスを許可することです。

OAuth 2.0 の文脈におけるフレームワークについては、私自身はまだしっくりくる説明が見つかっていません。e-Words の説明が近いのかな、と思っています。2

具体的なプログラムコードや設定ファイルなどのセットだけでなく、汎用的に適用できるプログラムの設計モデルや典型的な処理パターンなどを含めてフレームワークと呼ぶ場合もある。

OAuth がないとき

HTTP サービスのユーザーが HTTP サービスがホストする保護されたリソースへアクセスするには、認証情報(例:ユーザー名とパスワード)を用いてユーザー認証を行う必要があります。

それと同様に、サードパーティーアプリケーションが HTTP サービスがホストする保護されたリソースへアクセスするには、HTTP サービスのユーザーの認証情報を知る必要があります。しかし、それには次のような問題が存在します。

  • サードパーティーアプリケーションは HTTP サービスのユーザーの認証情報を保存する必要がある
  • サードパーティーアプリケーションは必要とするアクセス権以上の権限を持ってしまう
  • サードパーティーアプリケーションのアクセス権を削除するにはユーザーの認証情報を変更する必要がある

サードパーティーアプリケーションがユーザーの認証情報を保存する必要がある

サードパーティーアプリケーションの情報が漏洩した場合、HTTP サービスのユーザーの認証情報も漏洩してしまいます。

サードパーティーアプリケーションは必要とするアクセス権以上の権限を持ってしまう

例えば、サードパーティーアプリケーションが必要とする権限が HTTP サービスがホストする保護されたリソースへの読み取り権限のみだったとします。しかし、サードパーティーアプリケーションは HTTP サービスのユーザーの認証情報を使ってアクセスするため、実際は書き込み権限や削除権限など、そのユーザーと同等のアクセス権を持ってしまいます。

サードパーティーアプリケーションのアクセス権を削除するにはユーザーの認証情報を変更する必要がある

あるサードパーティーアプリケーションのアクセス権を削除したい場合、ユーザーの認証情報(例:パスワード)を変更する必要があります。その結果、他のサードパーティーアプリケーションのアクセス権も削除されてしまいます。他のサードパーティーアプリケーションも同じ認証情報を使って HTTP サービスがホストする保護されたリソースへアクセスしているためです。

OAuth があるとき

これらの問題を解決するのが OAuth 2.0 です。OAuth 2.0 ではサードパーティーアプリケーションは対象のユーザーの認証情報を知る必要はありません。認可サーバーと呼ばれるサーバーがサードパーティーアプリケーションに対してアクセストークンを発行し、それをサードパーティーアプリケーションが用いることで、HTTP サービスがホストする保護されたリソースへのアクセスが可能となります。

OAuth 2.0 の登場人物

OAuth 2.0 では 4 人の登場人物(ロールと呼びます)がいます。

  • リソースオーナー
  • クライアント
  • 認可サーバー
  • リソースサーバー

リソースオーナー

OAuth 2.0 とは」の HTTP サービスのユーザーのことです。リソースサーバーがホストする保護されたリソースの所有者です。クライアントのユーザーでもあります。

クライアント

リソースサーバーがホストする保護されたリソースを使い、何かしらのサービスを提供するアプリケーションです。保護されたリソースへアクセスするには、所有者であるリソースオーナーの許可を得る必要があります。

クライアントはコンフィデンシャルクライアントとパブリッククライアントの2種類があります。両者の違いは自身の認証情報(認可サーバーが発行するクライアント ID、クライアントパスワード)を安全に保存できるか否かです。

両者の違いについては Authlete の説明がわかりやすかったため、引用します。3

クライアントが自身の認証に必要な情報(クライアントシークレットや秘密鍵)を秘密に保つことが可能である場合、そのようなクライアントは confidential クライアントと呼ばれます。例えば、社内の閉じたネットワーク環境内に置かれて安全に守られたクライアントで、外部から攻撃を受けてクライアントシークレットを盗まれることはないと期待できるのであれば、それは confidential クライアントとみなすことができます。

一方、クライアントが自身の認証に必要な秘密情報を秘密に保つことが難しい場合、そのようなクライアントは public クライアントと呼ばれます。例えば、マーケットプレースに置かれて誰でもダウンロードできる状態にあるアプリケーション(一般的なスマートフォン用アプリケーション)の場合、ハッカーであればそのアプリケーションの中に埋め込まれたクライアントシークレットを抜き取ることが可能であると予想されるため、秘密情報を秘密に保つことが難しいと言えます。このようなクライアントは、public クライアントと呼ばれます。

認可サーバー

リソースサーバーがホストする保護されたリソースへのアクセス権をクライアントに付与するサーバーです。

リソースサーバー

保護されたリソースをホストするサーバーです。

OAuth 2.0 の権限付与タイプ

OAuth 2.0 では4つの権限付与タイプ(グラントタイプと呼びます)があります。

  • 認可コードグラント
  • インプリシットグラント
  • リソースオーナーパスワードクレデンシャルグラント
  • クライアントクレデンシャルグラント

認可コードグラント以外の権限付与タイプでクライアントがアクセストークンを取得するまでのフローについては省略します。

認可コードグラントでクライアントがアクセストークンを取得するまでのフロー

認可コードグラントでクライアントがアクセストークンを取得するまでのフローは次の通りです。図は RFC 6749 より引用しました。4

  +----------+
  | Resource |
  |   Owner  |
  |          |
  +----------+
       ^
       |
      (B)
  +----|-----+          Client Identifier       +---------------+
  |         -+----(A)-- & Redirection URI ---->|               |
  |  User-   |                                 | Authorization |
  |  Agent  -+----(B)-- User authenticates --->|     Server    |
  |          |                                 |               |
  |         -+----(C)-- Authorization Code ---<|               |
  +-|----|---+                                 +---------------+
    |    |                                         ^      v
   (A)  (C)                                        |      |
    |    |                                         |      |
    ^    v                                         |      |
  +---------+                                      |      |
  |         |>---(D)-- Authorization Code ---------'      |
  |  Client |          & Redirection URI                  |
  |         |                                             |
  |         |<---(E)----- Access Token -------------------'
  +---------+       (w/ Optional Refresh Token)
  1. クライアントがリソースオーナーを認可エンドポイントへリダイレクト(認可リクエスト)
  2. 認可サーバーがリソースオーナーを認証
  3. 認可サーバーがリソースオーナーにクライアントへのアクセス権の付与の可否を確認
  4. 認可サーバーが認可コードをブラウザ経由でクライアントに送付(認可レスポンス)
  5. クライアントが認可サーバーにアクセストークンを要求(トークンリクエスト)
  6. 認可サーバーがアクセストークンをクライアントに送付(トークンレスポンス)

なお、フローの開始前に、クライアントを認可サーバーに登録し、クライアントの認証情報(クライアント ID とクライアントパスワード)を発行しておきます。その際に、認可レスポンスで使用するリダイレクトエンドポイントを指定しておきます。

1. クライアントがリソースオーナーを認可エンドポイントへリダイレクト(認可リクエスト)

図の (A) に対応します。

フローを開始すると、クライアントはブラウザ経由でリソースオーナーを認可エンドポイントへリダイレクトします。認可エンドポイントは認可サーバーのエンドポイントです。認可エンドポイントは認可サーバーとリソースオーナー間でクライアントへのアクセス権の付与についてやりとりするために使われます。

クライアントは認可エンドポイントの URI にクエリパラメーターを付与します。クエリパラメーターの一覧は次の通りです。

  • response_type: code 固定
  • client_id: クライアント ID
  • redirect_uri: リダイレクトエンドポイント
  • scope: クライアントが要求するアクセス権
  • state: クロスサイトリクエストフォージェリを防ぐためのランダムな値

クライアント ID とリダイレクトエンドポイントはクライアントの事前登録時のものを指定します。

2. 認可サーバーがリソースオーナーを認証

図の (B) に対応します。

認可サーバーはリソースオーナーにログインページを表示します。リソースオーナーはログインページに自身の認証情報(例:ユーザー名、パスワード)を入力します。認可サーバーはリソースオーナーが入力した認証情報を用いて、リソースオーナーを認証します。

リソースオーナーの認証は認可サーバーとリソースオーナー間で行われるため、クライアントがリソースオーナーの認証情報を知ることはありません。

3. 認可サーバーがリソースオーナーにクライアントへのアクセス権の付与の可否

図の (B) に対応します。

認可サーバーはリソースオーナーにクライアントが要求するアクセス権を表示します。このとき表示されるアクセス権は「1. クライアントがリソースオーナーを認可エンドポイントへリダイレクト(認可リクエスト)」の scope の値に対応しています。

リソースオーナーは表示されたアクセス権を確認し、クライアントへのアクセス権の付与を許可します。

4. 認可サーバーが認可コードをブラウザ経由でクライアントに送付(認可レスポンス)

図の (C) に対応します。

認可サーバーはリソースオーナーがクライアントへのアクセス権の付与を許可した証として認可コードを発行します。認可サーバーはブラウザ経由でリソースオーナーをリダイレクトエンドポイントへリダイレクトします。リダイレクトエンドポイントはクライアントのエンドポイントで、クライアントの事前登録時に指定したものです。

認可サーバーはリダイレクトエンドポイントの URI にクエリパラメーターを付与します。クエリパラメーターの一覧は次の通りです

  • code: 認可コード
  • state: クロスサイトリクエストフォージェリを防ぐためのランダムな値

state は「1. クライアントがリソースオーナーを認可エンドポイントへリダイレクト(認可リクエスト)」の state の値と同じです。

5. クライアントが認可サーバーにアクセストークンを要求(トークンリクエスト)

図の (D) に対応します。

クライアントはアクセストークンを取得するため、トークンエンドポイントへリクエストを送信します。トークンエンドポイントは認可サーバーのエンドポイントです。

クライアントはトークンエンドポイントへのリクエストにボディーを含めます。リクエストボディーのパラメーターの一覧は次の通りです。

  • grant_type: authorization_code 固定
  • code: 認可コード
  • redirect_uri: リダイレクトエンドポイント
  • client_id: クライアント ID

認可コードは「4. 認可サーバーが認可コードをブラウザ経由でクライアントに送付(認可レスポンス) 」で取得したもの、クライアント ID とリダイレクトエンドポイントは、クライアントの事前登録時のものです。

また、クライアントがコンフィデンシャルクライアントの場合、認可サーバーはクライアントの認証情報(クライアント ID、クライアントパスワード)を使ってクライアントの認証を行う必要があります。クライアントの認証は Basic 認証を使うため、トークンエンドポイントへのリクエストに Authorization ヘッダーを含めます。この場合、リクエストボディーの client_id は不要です。

6. 認可サーバーがアクセストークンをクライアントに送付(トークンレスポンス)

図の (E) に対応します。

認可サーバーはアクセストークンを発行し、クライアントに送付します。

認可サーバーはトークンエンドポイントのレスポンスにボディーを含めます。レスポンスボディーのパラメーターの一覧は次の通りです。

  • access_token: アクセストークン
  • token_type: アクセストークンの種類
  • expires_in: アクセストークンの有効期限を秒数で表したもの
  • refresh_token: リフレッシュトークン

リフレッシュトークンはアクセストークンの再発行に使用します。リフレッシュトークンの発行は任意のため、レスポンスに含まれない場合もあります。

以上が、認可コードグラントでクライアントがアクセストークンを取得するまでのフローです。クライアントはこのフローで取得したアクセストークンを用いて、リソースサーバーがホストする保護されたリソースへアクセスします。

おわりに

OAuth 2.0 の概要と認可コードグラントでクライアントがアクセストークンを取得するまでのフローについてまとめました。

学習にあたり、Auth屋さん の『雰囲気でOAuth2.0を使っているエンジニアがOAuth2.0を整理して、手を動かしながら学べる本』を拝読しました。学習当初は「認証周りの話…🤔???」という程度のイメージ 5 しか持っていなかった私でしたが、Auth屋さんの本は非常にわかりやすく、短い時間で OAuth 2.0 の概要を把握できたように思います。これから OAuth 2.0 を学習したいと思っている方はご一読をお勧めします。

参考


  1. The OAuth 2.0 Authorization Framework より引用しました。

  2. https://e-words.jp/w/%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF.html

  3. https://kb.authlete.com/ja/s/operations/a/client-settings

  4. シーケンス図を描く予定だったのですが、トラックパッドでの作図が辛くて断念しました😭

  5. OAuth 2.0 は認可の話です。OAuth 認証と話が混ざっていたのではないかと思われます。