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

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

<sup>English version: **[Diagrams And Movies Of All The OAuth 2.0 Flows](https://medium.com/@darutk/diagrams-and-movies-of-all-the-oauth-2-0-flows-194f3c3ade85)**</sup>

**追記 (2019-07-02)**
認可決定エンドポイントからクライアントに認可コードやアクセストークンを渡す方法については、別記事『[OAuth 2.0 の認可レスポンスとリダイレクトに関する説明](https://qiita.com/TakahikoKawasaki/items/8567c80528da43c7e844)』で解説していますので、ご参照ください。

**追記（2020-03-20）**
この記事の内容を含む、筆者本人による『**[OAuth & OIDC 入門編](https://www.youtube.com/watch?v=PKPj_MmLq5E)**』解説動画を公開しました！


# **1. 認可コードフロー**

RFC 6749, [4.1. Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1) で定義されているフローです。認可エンドポイントに認可リクエストを投げ、応答として短命の認可コードを受けとり、その認可コードをトークンエンドポイントでアクセストークンと交換するフローです。

動画： [OAuth 2.0, Authorization Code Flow (in Japanese)](https://youtu.be/j0pIlZdD7-A)
<img width="720" alt="RFC6749-4_1-authorization_code_flow-Japanese.png" src="https://qiita-image-store.s3.amazonaws.com/0/106044/d9119f21-736d-d5ed-964d-3068af0fcde9.png">


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

```
GET {認可エンドポイント}
  ?response_type=code            // 必須
  &client_id={クライアントID}      // 必須
  &redirect_uri={リダイレクトURI}  // 条件により必須
  &scope={スコープ群}              // 任意
  &state={任意文字列}              // 推奨
  &code_challenge={チャレンジ}     // 任意
  &code_challege_method={メソッド} // 任意
  HTTP/1.1
HOST: {認可サーバー}
```
<sup>※：上記は、[RFC 6749](https://tools.ietf.org/html/rfc6749) に加え [RFC 7636](https://tools.ietf.org/html/rfc7636) で定義されたリクエストパラメーターも含んでいます。詳細は[こちら](https://qiita.com/TakahikoKawasaki/items/00f333c72ed96c4da659)。</sup>


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

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

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

```http
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 が含まれていれば必須
```
<sup>※：上記は、[RFC 6749](https://tools.ietf.org/html/rfc6749) に加え [RFC 7636](https://tools.ietf.org/html/rfc7636) で定義されたリクエストパラメーターも含んでいます。詳細は[こちら](https://qiita.com/TakahikoKawasaki/items/00f333c72ed96c4da659)。</sup>

クライアントのクライアントタイプが public の場合は `client_id` リクエストパラメーターが追加で必要です。一方、confidential の場合は、クライアント認証の方法により、`Authorization` ヘッダーや `client_id` & `client_secret` パラメーターなどが追加で必要になります。詳細は『[OAuth 2.0 クライアント認証](https://qiita.com/TakahikoKawasaki/items/63ed4a9d8d6e5109e401)』を参照してください。


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

```http
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](https://tools.ietf.org/html/rfc6749#section-4.2) で定義されているフローです。認可エンドポイントに認可リクエストを投げ、応答として直接アクセストークンを受け取るフローです。

動画： [OAuth 2.0, Implicit Flow (in Japanese)](https://youtu.be/fF1mJB64xAg)
<img width="720" alt="RFC6749-4_2-implicit_flow-Japanese.png" src="https://qiita-image-store.s3.amazonaws.com/0/106044/743e2d27-512d-f2b8-ee72-1a8c315b7f76.png">


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

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

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

```http
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](https://tools.ietf.org/html/rfc6749#section-4.3) で定義されているフローです。トークンエンドポイントにトークンリクエストを投げ、応答としてアクセストークンを受け取るフローです。OAuth のフローですが、クライアントアプリケーションがユーザーの ID とパスワードを受けとります。このフローについては、「[OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る](http://qiita.com/TakahikoKawasaki/items/f2a0d25a4f05790b3baa)」の「[Resource Owner Password Credentials Grant について](http://qiita.com/TakahikoKawasaki/items/f2a0d25a4f05790b3baa#resource-owner-password-credentials-grant-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)」もご参照ください。

動画： [OAuth 2.0, Resource Owner Password Credentials Flow (in Japanese)](https://youtu.be/qS0YY9Fo04Q)
![Resource-Owner-Password-Credentials-Flow-in-Japanese.png](https://qiita-image-store.s3.amazonaws.com/0/106044/f86d2e7c-6eb8-a4d4-05a8-b6fe367ea25e.png)


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

```http
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 クライアント認証](https://qiita.com/TakahikoKawasaki/items/63ed4a9d8d6e5109e401)』を参照してください。


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

```http
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](https://tools.ietf.org/html/rfc6749#section-4.4) で定義されているフローです。トークンエンドポイントにトークンリクエストを投げ、応答としてアクセストークンを受け取るフローです。このフローでは、ユーザーの認証はおこなわれず、クライアントアプリケーションの認証のみがおこなわれます。

動画： [OAuth 2.0, Client Credentials Flow (in Japanese)](https://youtu.be/LLIMOYk5Syc)
![Client-Credentials-Flow-in-Japanese.png](https://qiita-image-store.s3.amazonaws.com/0/106044/60324980-13ea-2138-2f8e-65e980cfccb3.png)


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

```http
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](https://tools.ietf.org/html/rfc6749#section-2.1) 参照) のみに許されており、結果、必ず[クライアント認証](https://tools.ietf.org/html/rfc6749#section-2.3)が求められます。

クライアント認証の方法により、`Authorization` ヘッダーや `client_id` & `client_secret` パラメーターなどが追加で必要になります。詳細は『[OAuth 2.0 クライアント認証](https://qiita.com/TakahikoKawasaki/items/63ed4a9d8d6e5109e401)』を参照してください。


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

```http
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](https://tools.ietf.org/html/rfc6749#section-6) で定義されているフローです。事前に発行を受けていたリフレッシュトークンをトークンエンドポイントに提示することにより、アクセストークンの再発行を受けます。

動画： [OAuth 2.0, Refresh Token Flow (in Japanese)](https://youtu.be/RncCqc-E_iM)
![Refresh-Token-Flow-in-Japanese.png](https://qiita-image-store.s3.amazonaws.com/0/106044/98fd8730-5007-8ffa-d743-81e951582532.png)


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

```http
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 クライアント認証](https://qiita.com/TakahikoKawasaki/items/63ed4a9d8d6e5109e401)』を参照してください。


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

```http
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](https://www.manning.com/books/oauth-2-in-action)』の著者としても知られる Justin Richer 氏が、2017 年 7 月 27 日に『[Deployment and Hosting Patterns in OAuth](https://medium.com/@justinsecurity/deployment-and-hosting-patterns-in-oauth-a1666dc0d966)』という記事を公開しました。 その記事の中で彼は、認可サーバーの実装方法を 4 つに分類し、『**Semi-Hosted Service パターン**』の例として **[Authlete](https://www.authlete.com/)**（オースリート）に言及しました。 詳細は『**[OAuth 2.0 / OIDC 実装の新アーキテクチャー](https://qiita.com/TakahikoKawasaki/items/b2a4fc39e0c1a1949aab)**』をご参照ください。

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

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

#### **認可コードフロー + Authlete**
![OAuth-Flows+Authlete-in-Japanese_2_Authorization-Code-Flow.png](https://qiita-image-store.s3.amazonaws.com/0/106044/5d4ba8ca-8b19-8e08-7ec2-61dcfaa1c618.png)

#### **インプリシットフロー + Authlete**
![OAuth-Flows+Authlete-in-Japanese_3_Implicit-Flow.png](https://qiita-image-store.s3.amazonaws.com/0/106044/4b9f4314-647a-c370-7eba-3de0b845d1af.png)

#### **リソースオーナー・パスワード・クレデンシャルズフロー + Authlete**
![OAuth-Flows+Authlete-in-Japanese_4_Resource-Owner-Password-Credentials-Flow.png](https://qiita-image-store.s3.amazonaws.com/0/106044/abfc19bf-6e67-256c-fdf9-9a9885175a6d.png)

#### **クライアント・クレデンシャルズフロー + Authlete**
![OAuth-Flows+Authlete-in-Japanese_5_Client-Credentials-Flow.png](https://qiita-image-store.s3.amazonaws.com/0/106044/4f6547e4-2023-d673-12da-248de8da3e0b.png)

#### **リフレッシュトークンフロー + Authlete**
![OAuth-Flows+Authlete-in-Japanese_6_Refresh-Token-Flow.png](https://qiita-image-store.s3.amazonaws.com/0/106044/da554f29-d7cb-f6cb-fe10-8a84f5315061.png)