RFC 6749 (The OAuth 2.0 Authorization Framework) で定義されている 4 つの認可フロー、および、リフレッシュトークンを用いてアクセストークンの再発行を受けるフローの図解及び動画です。動画は YouTube へのリンクとなっています。
English version: Diagrams And Movies Of All The OAuth 2.0 Flows
追記 (2019-07-02)
認可決定エンドポイントからクライアントに認可コードやアクセストークンを渡す方法については、別記事『OAuth 2.0 の認可レスポンスとリダイレクトに関する説明』で解説していますので、ご参照ください。
追記(2020-03-20)
この記事の内容を含む、筆者本人による『OAuth & OIDC 入門編』解説動画を公開しました!
1. 認可コードフロー
RFC 6749, 4.1. Authorization Code Grant で定義されているフローです。認可エンドポイントに認可リクエストを投げ、応答として短命の認可コードを受けとり、その認可コードをトークンエンドポイントでアクセストークンと交換するフローです。
動画: OAuth 2.0, Authorization Code Flow (in Japanese)
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 で定義されたリクエストパラメーターも含んでいます。詳細はこちら。
クライアントのクライアントタイプが public の場合は client_id
リクエストパラメーターが追加で必要です。一方、confidential の場合は、クライアント認証の方法により、Authorization
ヘッダーや client_id
& client_secret
パラメーターなどが追加で必要になります。詳細は『OAuth 2.0 クライアント認証』を参照してください。
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)
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)
3.1. トークンエンドポイントへのリクエスト
POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Content-Type: application/x-www-form-urlencoded
grant_type=password // 必須
&username={ユーザーID} // 必須
&password={パスワード} // 必須
&scope={スコープ群} // 任意
クライアントのクライアントタイプが public の場合は client_id
リクエストパラメーターが追加で必要です。一方、confidential の場合は、クライアント認証の方法により、Authorization
ヘッダーや client_id
& client_secret
パラメーターなどが追加で必要になります。詳細は『OAuth 2.0 クライアント認証』を参照してください。
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)
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 参照) のみに許されており、結果、必ずクライアント認証が求められます。
クライアント認証の方法により、Authorization
ヘッダーや client_id
& client_secret
パラメーターなどが追加で必要になります。詳細は『OAuth 2.0 クライアント認証』を参照してください。
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)
5.1. トークンエンドポイントへのリクエスト
POST {トークンエンドポイント} HTTP/1.1
Host: {認可サーバー}
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token // 必須
&refresh_token={リフレッシュトークン} // 必須
&scope={スコープ群} // 任意
クライアントのクライアントタイプが public の場合は client_id
リクエストパラメーターが追加で必要です。一方、confidential の場合は、クライアント認証の方法により、Authorization
ヘッダーや client_id
& client_secret
パラメーターなどが追加で必要になります。詳細は『OAuth 2.0 クライアント認証』を参照してください。
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 がどうして「どんなユーザー認証方法とも組み合わせることができる」のかが分かると思います。