OAuth 2.0 全フローの図解と動画

  • 1175
    Like
  • 0
    Comment

RFC 6749 (The OAuth 2.0 Authorization Framework) で定義されている 4 つの認可フロー、および、リフレッシュトークンを用いてアクセストークンの再発行を受けるフローの図解及び動画です。動画は YouTube へのリンクとなっています。

English version: Diagrams And Movies Of All The OAuth 2.0 Flows

1. 認可コードフロー

RFC 6749, 4.1. Authorization Code Grant で定義されているフローです。認可エンドポイントに認可リクエストを投げ、応答として短命の認可コードを受けとり、その認可コードをトークンエンドポイントでアクセストークンと交換するフローです。

動画: OAuth 2.0, Authorization Code Flow (in Japanese)
RFC6749-4_1-authorization_code_flow-Japanese.png

1.1. 認可エンドポイントへのリクエスト

GET {認可エンドポイント}
  ?response_type=code              // 必須
  &client_id={クライアントID}      // 必須
  &redirect_uri={リダイレクトURI}  // 条件により必須
  &scope={スコープ群}              // 任意
  &state={任意文字列}              // 推奨
  &code_challenge={チャレンジ}     // 任意
  &code_challege_method={メソッド} // 任意
  HTTP/1.1
HOST: {認可サーバー}

※:上記は、RFC 6749 に加え RFC 7636 で定義されたリクエストパラメーターも含んでいます。詳細はこちら

1.2. 認可エンドポイントからのレスポンス

HTTP/1.1 302 Found
Location: {リダイレクトURI}
  ?code={認可コード}        // 必須
  &state={任意文字列}       // 認可リクエストに state が含まれていれば必須

1.3. トークンエンドポイントへのリクエスト

POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code     // 必須
&code={認可コード}                // 必須 認可エンドポイントのレスポンスに含まれる値を指定
&redirect_uri={リダイレクトURI}   // 認可リクエストに redirect_uri が含まれていれば必須
&code_verifier={ベリファイア}     // 認可リクエストに code_challenge が含まれていれば必須

※:上記は、RFC 6749 に加え RFC 7636 で定義されたリクエストパラメーターも含んでいます。詳細はこちら

条件によってはクライアント認証を求められることがあり、その場合は Basic 認証(Authorization ヘッダー)もしくは client_id & client_secret パラメーターを追加します。

1.4. トークンエンドポイントからのレスポンス

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"{アクセストークン}",      // 必須
  "token_type":"{トークンタイプ}",          // 必須
  "expires_in":{有効秒数},                  // 任意
  "refresh_token":"{リフレッシュトークン}", // 任意
  "scope":"{スコープ群}"                    // 要求したスコープ群と差異があれば必須
}

2. インプリシットフロー

RFC 6749, 4.2. Implicit Grant で定義されているフローです。認可エンドポイントに認可リクエストを投げ、応答として直接アクセストークンを受け取るフローです。

動画: OAuth 2.0, Implicit Flow (in Japanese)
RFC6749-4_2-implicit_flow-Japanese.png

2.1. 認可エンドポイントへのリクエスト

GET {認可エンドポイント}
  ?response_type=token             // 必須
  &client_id={クライアントID}      // 必須
  &redirect_uri={リダイレクトURI}  // 条件により必須
  &scope={スコープ群}              // 任意
  &state={任意文字列}              // 推奨
  HTTP/1.1
HOST: {認可サーバー}

2.2. 認可エンドポイントからのレスポンス

HTTP/1.1 302 Found
Location: {リダイレクトURI}
  #access_token={アクセストークン} // 必須
  &token_type={トークンタイプ}     // 必須
  &expires_in={有効秒数}           // 任意
  &state={任意文字列}              // 認可リクエストに state が含まれていれば必須
  &scope={スコープ群}              // 要求したスコープ群と差異があれば必須

インプリシットフローではリフレッシュトークンは発行されません。

3. リソースオーナー・パスワード・クレデンシャルズフロー

RFC 6749, 4.3. Resource Owner Password Credentials Grant で定義されているフローです。トークンエンドポイントにトークンリクエストを投げ、応答としてアクセストークンを受け取るフローです。OAuth のフローですが、クライアントアプリケーションがユーザーの ID とパスワードを受けとります。このフローについては、「OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る」の「Resource Owner Password Credentials Grant について」もご参照ください。

動画: OAuth 2.0, Resource Owner Password Credentials Flow (in Japanese)
Resource-Owner-Password-Credentials-Flow-in-Japanese.png

3.1. トークンエンドポイントへのリクエスト

POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Content-Type: application/x-www-form-urlencoded

grant_type=password       // 必須
&username={ユーザーID}    // 必須
&password={パスワード}    // 必須
&scope={スコープ群}       // 任意

条件によってはクライアント認証を求められることがあり、その場合は Basic 認証(Authorization ヘッダー)もしくは client_id & client_secret パラメーターを追加します。

3.2. トークンエンドポイントからのレスポンス

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"{アクセストークン}",      // 必須
  "token_type":"{トークンタイプ}",          // 必須
  "expires_in":{有効秒数},                  // 任意
  "refresh_token":"{リフレッシュトークン}", // 任意
  "scope":"{スコープ群}"                    // 要求したスコープ群と差異があれば必須
}

4. クライアント・クレデンシャルズフロー

RFC 6749, 4.4. Client Credentials Grant で定義されているフローです。トークンエンドポイントにトークンリクエストを投げ、応答としてアクセストークンを受け取るフローです。このフローでは、ユーザーの認証はおこなわれず、クライアントアプリケーションの認証のみがおこなわれます。

動画: OAuth 2.0, Client Credentials Flow (in Japanese)
Client-Credentials-Flow-in-Japanese.png

4.1. トークンエンドポイントへのリクエスト

POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Authorization: Basic {クライアントクレデンシャルズ}
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials     // 必須
&scope={スコープ群}               // 任意

クライアント・クレデンシャルズフローは、confidential クライアント (RFC 6749, 2.1. Client Types 参照) のみに許されており、結果、必ずクライアント認証が求められます。Basic 認証(Authorization ヘッダー)もしくは client_id & client_secret パラメーターが必要になります。

4.2. トークンエンドポイントからのレスポンス

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"{アクセストークン}",  // 必須
  "token_type":"{トークンタイプ}",      // 必須
  "expires_in":{有効秒数},              // 任意
  "scope":"{スコープ群}"                // 要求したスコープ群と差異があれば必須
}

クライアント・クレデンシャルズフローでは、リフレッシュトークンを発行すべきではないとされています。

5. リフレッシュトークンフロー

RFC 6749, 6. Refreshing an Access Token で定義されているフローです。事前に発行を受けていたリフレッシュトークンをトークンエンドポイントに提示することにより、アクセストークンの再発行を受けます。

動画: OAuth 2.0, Refresh Token Flow (in Japanese)
Refresh-Token-Flow-in-Japanese.png

5.1. トークンエンドポイントへのリクエスト

POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token               // 必須
&refresh_token={リフレッシュトークン}  // 必須
&scope={スコープ群}                    // 任意

条件によってはクライアント認証を求められることがあり、その場合は Basic 認証(Authorization ヘッダー)もしくは client_id & client_secret パラメーターを追加します。

5.2. トークンエンドポイントからのレスポンス

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"{アクセストークン}",      // 必須
  "token_type":"{トークンタイプ}",          // 必須
  "expires_in":{有効秒数},                  // 任意
  "refresh_token":"{リフレッシュトークン}", // 任意
  "scope":"{スコープ群}"                    // 元のスコープ群と差異があれば必須
}

まとめ

フロー 認可エンドポイント トークンエンドポイント 特徴
認可コード 使う 使う 短命の認可コードの発行を受け、トークンエンドポイントでアクセストークンと交換する。
インプリシット 使う 使わない 認可エンドポイントから直接アクセストークンの発行を受ける。
リソースオーナー・パスワード・クレデンシャルズ 使わない 使う ユーザーの ID とパスワードをクライアントに渡す。
クライアント・クレデンシャルズ 使わない 使う クライアントアプリの認証のみでアクセストークンの発行を受ける。
リフレッシュトークン 使わない 使う リフレッシュトークンを提示してアクセストークンの再発行を受ける。

おまけ

OAuth 2.0 や OpenID Connect、UMA など、数多くの標準仕様の策定に携わり、『OAuth 2 in Action』の著者としても知られる Justin Richer 氏が、2017 年 7 月 27 日に『Deployment and Hosting Patterns in OAuth』という記事を公開しました。 その記事の中で彼は、認可サーバーの実装方法を 4 つに分類し、『Semi-Hosted Service パターン』の例として Authlete(オースリート)に言及しました。 詳細は『OAuth 2.0 / OIDC 実装の新アーキテクチャー』をご参照ください。

Semi-Hosted Service パターンでは、認可機能を提供するバックエンドサービスを利用して、フロントの認可サーバーを実装します。 この実装方法のアーキテクチャーは通常の認可サーバーのそれより当然複雑になりますが、その利点は何かというと、バックエンドサービスが OAuth 2.0 と OpenID Connect の実装に専門特化できることです。 アイデンティティー管理やユーザー認証、セッション管理、API 管理、不正検出など、API まわりの他の技術要素から独立し、OAuth 2.0 と OpenID Connect の実装に集中することができます。 このアーキテクチャーから必然的に導かれるもう一つの利点は、バックエンドサービス(OAuth 2.0 と OpenID Connect の実装)を、他の技術要素のどのようなソリューションとも組み合わせることができることです。 例えば、ユーザー認証にどのような方法を用いてもよく、FIDO のような新しい認証ソリューションが登場しても、問題無く対応できます。

ここでは、おまけとして、Authlete をバックエンドサービスとして用いたときに OAuth 2.0 の各フローがどのように実装されることになるかを、図でご紹介します。 丁寧に図を見ていただくと、Authlete がどうして「どんなユーザー認証方法とも組み合わせることができる」のかが分かると思います。

認可コードフロー + Authlete

OAuth-Flows+Authlete-in-Japanese_2_Authorization-Code-Flow.png

インプリシットフロー + Authlete

OAuth-Flows+Authlete-in-Japanese_3_Implicit-Flow.png

リソースオーナー・パスワード・クレデンシャルズフロー + Authlete

OAuth-Flows+Authlete-in-Japanese_4_Resource-Owner-Password-Credentials-Flow.png

クライアント・クレデンシャルズフロー + Authlete

OAuth-Flows+Authlete-in-Japanese_5_Client-Credentials-Flow.png

リフレッシュトークンフロー + Authlete

OAuth-Flows+Authlete-in-Japanese_6_Refresh-Token-Flow.png