OAuth & OpenID Connect 関連仕様まとめ

# はじめに

**OAuth** や **[OpenID Connect](http://openid.net/connect/)** に関連する仕様を紹介していこうと思います。

仕様はたくさんあるものの、ほとんどオプショナルです。しかし、「**認可サーバーを実装する際は、[RFC 6749](https://tools.ietf.org/html/rfc6749) だけではなく、認可コード横取り攻撃への対抗策である [RFC 7636](https://tools.ietf.org/html/rfc7636) も実装すべきである**」<sup>*</sup> という点は強調しておきたいと思います。

<sup>* 「[PKCE: 認可コード横取り攻撃対策のために OAuth サーバーとクライアントが実装すべきこと](http://qiita.com/TakahikoKawasaki/items/00f333c72ed96c4da659)」という記事もご参照ください。</sup>


# **1. OAuth 2.0 (RFC 6749)**

**OAuth 2.0** の仕様の本体は **[RFC 6749](https://tools.ietf.org/html/rfc6749)** (The OAuth 2.0 Authorization Framework) です。RFC 6749 の解説記事は世の中にたくさんあるので、ここでは要点だけ手短に紹介します。

RFC 6749 は、アクセストークンを発行する手段として、次の 4 つのフローを定義しています。

  1. [Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1) (認可コードフロー)
  2. [Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2) (インプリシットフロー)
  3. [Resource Owner Password Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.3) (パスワードフロー)
  4. [Client Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.4) (クライアント認証情報フロー)

<sup>(上記の日本語訳は私が恣意的につけたもので、特に 3., 4. については世の中で合意が取れているわけではありません。)</sup>

加えて、リフレッシュトークンを使って新しいアクセストークンを取得するフローも定義しています (RFC 6749, [6. Refreshing an Access Token](https://tools.ietf.org/html/rfc6749#section-6))。

アクセストークンを発行するサーバー、いわゆる**認可サーバー**は、これらのフローを実現するため、次の二つのエンドポイントを実装します。

  1. **[認可エンドポイント](https://tools.ietf.org/html/rfc6749#section-3.1)**
  2. **[トークンエンドポイント](https://tools.ietf.org/html/rfc6749#section-3.2)**

インプリシットフローしかサポートしないのであれば、認可エンドポイントを実装するだけで済みます。また、パスワードフローやクライアント認証情報フローだけであれば、トークンエンドポイントの実装だけで済みます。


# **2. Bearer Token Usage (RFC 6750)**

認可サーバーにより発行されたアクセストークンを、保護リソースエンドポイント (狭義の Web API) に渡す方法を定めた仕様が、**[RFC 6750](https://tools.ietf.org/html/rfc6750)** (The OAuth 2.0 Authorization Framework: Bearer Token Usage) です。RFC 6750 では、次の 3 つの方法を定義しています。

  1. [Authorization ヘッダーに埋め込む方法](https://tools.ietf.org/html/rfc6750#section-2.1)
  2. [リクエストボディーに埋め込む方法](https://tools.ietf.org/html/rfc6750#section-2.2)
  3. [クエリーパラメーターとして渡す方法](https://tools.ietf.org/html/rfc6750#section-2.3)


# **3. OAuth 1.0 (RFC 5849)**

**OAuth 1.0** は **[RFC 5849](https://tools.ietf.org/html/rfc5849)** (The OAuth 1.0 Protocol) で定められていますが、この仕様は [RFC 6749](https://tools.ietf.org/html/rfc6749) の策定をもって廃止されました。OAuth 1.0a というように、1.0 の後ろに a がつく表記を見かけることがあると思いますが、下表に示すように、1.0a よりも RFC 5849 の方が新しい仕様です。

| 策定月 | 仕様 |
|:--|:--|
| 2007 年 12 月 | [OAuth Core 1.0](http://oauth.net/core/1.0/) |
| 2009 年 6 月 | [OAuth Core 1.0 Revision A](http://oauth.net/core/1.0a/) |
| 2010 年 4 月 | [RFC 5849](https://tools.ietf.org/html/rfc5849) &nbsp; (The OAuth 1.0 Protocol) |

「[OAuth 1.0 のほうが OAuth 2.0 より安全なの？](http://qiita.com/TakahikoKawasaki/items/3600b28af7b63671b968)」という記事もご参照ください。


# **4. OAuth 2.0 の脅威モデルとセキュリティー考慮事項 (RFC 6819)**

OAuth 2.0 の実装にあたり、特にセキュリティーに関して考慮すべき事項が、**[RFC 6819](https://tools.ietf.org/html/rfc6819)** (OAuth 2.0 Threat Model and Security Considerations) に挙げられています。


# **5. トークン取り消し (RFC 7009)**

発行されたアクセストークンやリフレッシュトークンを取り消すための手段が、**[RFC 7009](https://tools.ietf.org/html/rfc7009)** (OAuth 2.0 Token Revocation) で定められています。この仕様をサポートする認可サーバーは、トークンを取り消すためのエンドポイントを公開します。そのエンドポイントに次のパラメーターを渡すことで、トークンを取り消すことができます。

| パラメーター | 要否 | 説明 |
|:--|:-:|:--|
| `token` | 必須 | 取り消したいトークン |
| `token_type_hint` | 任意 | トークンの種類。`access_token` もしくは `refresh_token`。 |


# **6. トークン情報取得 (RFC 7662)**

アクセストークンやリフレッシュトークンの情報を取得するための手段が、**[RFC 7662](https://tools.ietf.org/html/rfc7662)** (OAuth 2.0 Token Introspection) で定められています。この仕様をサポートする認可サーバーは、トークンの情報を返すエンドポイントを公開します。そのエンドポイントに次のパラメーターを渡すことで、トークンに関する情報を取得することができます。

| パラメーター | 要否 | 説明 |
|:--|:-:|:--|
| `token` | 必須 | 情報を取得したいトークン |
| `token_type_hint` | 任意 | トークンの種類。`access_token` もしくは `refresh_token`。 |

情報は JSON フォーマットで返ってきます。詳細は [RFC 7662, 2.2. Introspection Response](https://tools.ietf.org/html/rfc7662#section-2.2) を参照してください。


# **7. 認可コード横取り攻撃への対抗策 (RFC 7636)**

[認可コードフロー](https://tools.ietf.org/html/rfc6749#section-4.1)により発行された認可コードをクライアントアプリケーションが受け取る際、悪意のあるアプリケーションがその認可コードを横取りするという攻撃 (authorization code interception attack) があります。この攻撃への対抗策として定められた仕様が **[RFC 7636](https://tools.ietf.org/html/rfc7636)** (Proof Key for Code Exchange by OAuth Public Clients) です。

RFC 7636 をサポートする認可サーバーの[認可エンドポイント](https://tools.ietf.org/html/rfc6749#section-3.1)は、次の二つのパラメーターを受け付けます。

| パラメーター | 要否 | 説明 |
|:--|:-:|:--|
| `code_challenge` | 必須 | 任意の値である Code Verifier を元に計算された Code Challenge の値 |
| `code_challenge_method` | 任意 | Code Challenge の計算に用いるメソッド。`plain` (デフォルト) もしくは `S256`。 |

また、[トークンエンドポイント](https://tools.ietf.org/html/rfc6749#section-3.2)で次のパラメーターを受け取ります。

| パラメーター | 要否 | 説明 |
|:--|:--|:--|
| `code_verifier` | 認可リクエストの際に `code_challenge` パラメーターを付けていた場合は必須 | 認可リクエストの際に渡した Code Challenge の元となった Code Verifier の値 |

トークンエンドポイントの実装内で、提示された Code Verifier の値から Code Challenge を計算し、その計算結果を認可リクエストの際に提示された Code Challenge の値と比較することで、認可コードを要求したクライアントアプリケーションとアクセストークンを要求したクライアントアプリケーションが同一であることを確認します。これにより、認可コードを横取りした悪意のあるクライアントアプリケーションにアクセストークンが発行されることを防ぐことができます。

この手順の図解は「[Proof Key for Code Exchange (RFC 7636)](https://www.authlete.com/documents/article/pkce)」にありますのでご参照ください。また、実装については、「[PKCE: 認可コード横取り攻撃対策のために OAuth サーバーとクライアントが実装すべきこと](http://qiita.com/TakahikoKawasaki/items/00f333c72ed96c4da659)」という記事をご参照ください。


# **8. OpenID Connect Core 1.0**

**[OpenID Connect](http://openid.net/connect/)** の中心となる仕様が **[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html)** です。この仕様書の柱は、**ID トークン**の基本構造 ([2. ID Token](http://openid.net/specs/openid-connect-core-1_0.html#IDToken))、ID トークンの取得方法 ([3. Authentication](http://openid.net/specs/openid-connect-core-1_0.html#Authentication))、ID トークンに含めるユーザー属性の種類 ([5.1. Standard Claims](http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims))、ユーザー情報エンドポイント ([5.3. UserInfo Endpoint](http://openid.net/specs/openid-connect-core-1_0.html#UserInfo)) です。

OpenID Connect による認証の結果、ID トークンが発行されます。ID トークンには、認証されたユーザーの一意識別子 (subject) の他、オプショナルですがユーザーの属性情報 (claims) が含まれます。しかし、より重要なのは、ID トークンに付与されている署名を検証することで、ID トークンの出所を明らかにすることができる点です。これが、単なるユーザー情報を集めた JSON と ID トークンの大きな違いです。

OpenID Connect Core 1.0 内の個々の仕様については、後ほど言及します。


# **9. JSON Web Token 関連仕様**

OpenID Connect により発行される ID トークンは、**JSON Web Token** の一種です。JSON Web Token は **JWT** と短く表現されることがあり、この省略形は「ジョット」と読みます ([RFC 7519, 1. Introduction](https://tools.ietf.org/html/rfc7519#section-1))。JWT の仕様を定めたものが **[RFC 7519](https://tools.ietf.org/html/rfc7519)** です。

JWT は、JSON オブジェクトを、**JWS** または **JWE** の形式で、もしくは JWS と JWE を組み合わせた形式で表現したものです。ここで、JWS と JWE は、**JSON Web Signature** と **JSON Web Encryption** の略であり、それぞれ、**[RFC 7515](https://tools.ietf.org/html/rfc7515)** と **[RFC 7516](https://tools.ietf.org/html/rfc7516)** で仕様が定められています。

JWS や JWE では、署名処理や暗号処理の話が出てきますが、これらの処理で使われる署名アルゴリズムや暗号アルゴリズムについては、あえて別の仕様書に記述されています。その別仕様書が、**[RFC 7518](https://tools.ietf.org/html/rfc7518)**「**JSON Web Algorithms** (**JWA**)」です。

署名処理や暗号処理で非対称鍵系アルゴリズムが使われている場合、何らかの方法で公開鍵が公開されている必要があります。その表現方法として新たに定められたのが **[RFC 7517](https://tools.ietf.org/html/rfc7517)**「**JSON Web Key** (**JWK**)」という仕様です。

一気にいろいろ出てきましたが、まとめると次の表のとおりです。

| 仕様書 | 省略形 | 名称 |
|:-:|:-:|:--|
| [RFC 7515](https://tools.ietf.org/html/rfc7515) | JWS | JSON Web Signature |
| [RFC 7516](https://tools.ietf.org/html/rfc7516) | JWE | JSON Web Encryption |
| [RFC 7517](https://tools.ietf.org/html/rfc7517) | JWK | JSON Web Key |
| [RFC 7518](https://tools.ietf.org/html/rfc7518) | JWA | JSON Web Algorithms |
| [RFC 7519](https://tools.ietf.org/html/rfc7519) | JWT | JSON Web Token |


# **10. OpenID Connect Discovery 1.0**

OpenID プロバイダーに関する情報を取得する手段として、**[OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html)** という仕様が定義されています。

この仕様がサポートされている場合、その OpenID プロバイダーの発行者識別子 (`https://` で始まる URI) に `/.well-known/openid-configuration` を付けた URL に HTTP GET リクエストを投げることで、当該 OpenID プロバイダーの情報を取得することができます。情報は JSON で返されます。その JSON には、[3. OpenID Provider Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) に列挙されている情報が含まれています。

[4.2. OpenID Provider Configuration Response](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse) には、JSON の例が載せられています。また、実例として、Google 社の実装はこちらになります。

[https://accounts.google.com/.well-known/openid-configuration](https://accounts.google.com/.well-known/openid-configuration)

なお、Google の実装には `code_challenge_methods_supported` というパラメーターが含まれていますが、これは、ドラフト段階にある **[OAuth 2.0 Authorization Server Discovery Metadata](https://tools.ietf.org/html/draft-ietf-oauth-discovery)** の仕様を取り込んだ結果です。


# **11. OpenID Connect Dynamic Client Registration 1.0**

クライアントアプリケーションを OpenID プロバイダーに登録する手段として、**[OpenID Connect Dynamic Client Registration 1.0](http://openid.net/specs/openid-connect-registration-1_0.html)** という仕様が定義されています。

この仕様をサポートする OpenID プロバイダーは、クライアントアプリケーション登録用のエンドポイントを公開します。そのエンドポイントに、[2. Client Metadata](http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata) に列挙されている情報を含む JSON を HTTP POST で渡すことで、クライアントアプリケーションを登録することができます。


# **12. 応答タイプ (response_type)**

認可リクエスト (OpenID Connect の文脈では認証リクエスト) を[認可エンドポイント](https://tools.ietf.org/html/rfc6749#section-3.1)に投げる際、`response_type` パラメーターを用いて、認可サーバーから何を返してもらうかを指定します。[RFC 6749](https://tools.ietf.org/html/rfc6749) を素直に読むと、`response_type` が取る値は `code` か `token` かの二者択一となります。`code` の場合は[認可コードフロー](https://tools.ietf.org/html/rfc6749#section-4.1)により認可コードが、`token` の場合は[インプリシットフロー](https://tools.ietf.org/html/rfc6749#section-4.2)によりアクセストークンが、認可エンドポイントからクライアントアプリケーションに返されます。

しかし、OpenID Connect により、`response_type` が取る値は、「`code`, `id_token`, `token` の任意の組み合わせ」か、もしくは `none`、となりました。これについては、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の [3. Authentication](http://openid.net/specs/openid-connect-core-1_0.html#Authentication) および **[OAuth 2.0 Multiple Response Type Encoding Practices](http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html)** で詳しく説明されています。

`response_type` に `id_token` が含まれている場合、[認可エンドポイント](https://tools.ietf.org/html/rfc6749#section-3.1)からの応答に ID トークンが含まれます。また、`response_type` に `id_token` が含まれていなくとも、`code` が含まれていて、かつ、`scope` に `openid` が含まれている場合、[トークンエンドポイント](https://tools.ietf.org/html/rfc6749#section-3.2)からの応答に ID トークンが含まれることになります。

`response_type` に `code`, `id_token`, `token` の全てが含まれている場合、認可エンドポイントからは、認可コード、ID トークン、アクセストークンの 3 つが返ってくることになります。

`response_type` パラメーターの取りうる値が二者択一の状態から「`code`, `id_token`, `token` の任意の組み合わせ」に変更になったことが、既存の認可サーバーの実装に与える影響の大きさについては、「[OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る](http://qiita.com/TakahikoKawasaki/items/f2a0d25a4f05790b3baa)」の「[応答タイプ (response_type)](http://qiita.com/TakahikoKawasaki/items/f2a0d25a4f05790b3baa#%E5%BF%9C%E7%AD%94%E3%82%BF%E3%82%A4%E3%83%97-response_type)」を参照してください。


# **13. 応答モード (response_mode)**

[認可コードフロー](https://tools.ietf.org/html/rfc6749#section-4.1)では、応答パラメーター群はリダイレクト URI のクエリー部に入ります ([4.1.2. Authorization Response](https://tools.ietf.org/html/rfc6749#section-4.1.2))。一方、[インプリシットフロー](https://tools.ietf.org/html/rfc6749#section-4.1)では、応答パラメーター群はフラグメント部に入ります ([4.2.2. Access Token Response](https://tools.ietf.org/html/rfc6749#section-4.2.2))。このように、[RFC 6749](https://tools.ietf.org/html/rfc6749) では、フローの種類に基づいて応答パラメーターを入れる場所が決まるルールとなっています。

この状況に対し、**[OAuth 2.0 Multiple Response Type Encoding Practices](http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html)** という仕様で、応答パラメーター群を入れる場所を制御するためのパラメーターとして、`response_mode` が追加されました。このパラメーターの値を `query` とするとクエリー部に、`fragment` にするとフラグメント部に応答パラメーター群が入るようになります。

また、**[OAuth 2.0 Form Post Response Mode](http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html)** という仕様により、`response_mode` パラメーターの値として、`form_post` が追加されました。`form_post` を指定すると、認可リクエストに対する認可サーバーの応答は「302 Found + Location ヘッダー」ではなく、「200 OK + HTTP POST を自動実行する HTML」となります。このため、リダイレクトエンドポイントの実装は、(クエリーパラメーター群やフラグメントパラメーター群ではなく) HTTP POST リクエストのリクエストボディーを処理することになります。

なお、応答パラメーターを入れる場所のデフォルト値がフラグメント部である場合、`response_mode=query` を用いても、応答パラメーターをクエリー部で受け取ることはできません (仕様により禁止されています)。

下表は、「`response_type` と `response_mode` の組み合わせ」と「HTTP ステータスと応答パラメーターの格納場所」の関係を示したものです。

<table>
  <tr>
    <th rowspan="3">response_type</th>
    <th colspan="4">response_mode</th>
  </tr>
  <tr>
    <th>(default)</th>
    <th>query</th>
    <th>fragment</th>
    <th>form_post</th>
  </tr>
  <tr>
    <th colspan="3">302 Found</th>
    <th>200 OK</th>
  </tr>
  <tr>
    <td>none</td>
    <td rowspan="2">クエリー部</td>
    <td rowspan="2">クエリー部</td>
    <td rowspan="2">フラグメント部</td>
    <td rowspan="2">HTML FORM 内</td>
  </tr>
  <tr>
    <td>code</td>
  </tr>
  <tr>
    <td>token</td>
    <td rowspan="6">フラグメント部</td>
    <td rowspan="6">不可</td>
    <td rowspan="6">フラグメント部</td>
    <td rowspan="6">HTML FORM 内</td>
  </tr>
  <tr>
    <td>id_token</td>
  </tr>
  <tr>
    <td>code token</td>
  </tr>
  <tr>
    <td>code id_token</td>
  </tr>
  <tr>
    <td>id_token token</td>
  </tr>
  <tr>
    <td>code id_token token</td>
  </tr>
</table>


# **14. ユーザー情報エンドポイント**

[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の [5.3. UserInfo Endpoint](http://openid.net/specs/openid-connect-core-1_0.html#UserInfo) では、保護リソースエンドポイントの一種として、**ユーザー情報エンドポイント**の仕様を定義しています。このエンドポイントからは、[ID トークン](http://openid.net/specs/openid-connect-core-1_0.html#IDToken)相当の情報が、[JWT](https://tools.ietf.org/html/rfc7519) 形式もしくは JSON 形式で返されます。どちらの形式で返されるかは、クライアントアプリケーションの `userinfo_signed_response_alg` 属性が設定されているかどうかで決まります。`userinfo_signed_response_alg` は、[OpenID Connect Dynamic Client Registration 1.0](http://openid.net/specs/openid-connect-registration-1_0.html) の [2. Client Metadata](http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata) で定義されています。 `userinfo_signed_response_alg` については、「[署名アルゴリズム](http://qiita.com/TakahikoKawasaki/items/f2a0d25a4f05790b3baa#%E7%BD%B2%E5%90%8D%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0)」の議論もご参照ください。

なお、OpenID プロバイダーは、ユーザー情報エンドポイントから返す JWT の署名・暗号アルゴリズムとしてサポートするものを、次のパラメーター群を Discovery 情報に含めることで公開できます。詳細は [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) の [3. OpenID Provider Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) を参照してください。

* `userinfo_signing_alg_values_supported`
* `userinfo_encryption_alg_values_supported`
* `userinfo_encryption_enc_values_supported`


# **15. クレーム (claim)**

OpenID プロバイダーから発行される [ID トークン](http://openid.net/specs/openid-connect-core-1_0.html#IDToken)に含まれるユーザー属性情報群は、**クレーム** (claim) と呼ばれます。[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の [5.1. Standard Claims](http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) では、下表のような標準クレーム群が定義されています。

| クレーム名               | 説明
|:------------------------|:----|
| `sub`                   | ユーザーの一意識別子 |
| `name`                  | フルネーム |
| `given_name`            | 名前 |
| `family_name`           | 苗字 |
| `middle_name`           | ミドルネーム |
| `nickname`              | ニックネーム |
| `preferred_username`    | 希望のユーザー名|
| `profile`               | プロフィールページの URL |
| `picture`               | プロフィール画像の URL |
| `website`               | ウェブサイトもしくはブログの URL |
| `email`                 | メールアドレス |
| `email_verified`        | メールアドレスが検証済みかどうかを示す真偽値 |
| `gender`                | 性別 |
| `birthdate`             | 誕生日 |
| `zoneinfo`              | 地域情報 |
| `locale`                | ロケール情報 |
| `phone_number`          | 電話番号 |
| `phone_number_verified` | 電話番号が検証済みかどうかを示す真偽値 |
| `address`               | 住所 |
| `updated_at`            | 情報最終更新時刻 |

ID トークンに含めるクレームの種類を、クライアントアプリケーション側から要求することができます。要求方法は二つあり、一つは、`scope` パラメーターにクレームグループの名称を含める方法 ([5.4. Requesting Claims using Scope Values](http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims))、もう一つは、`claims` パラメーターを用いて要求するクレーム群を指定する方法 ([5.5. Requesting Claims using the "claims" Request Parameter](http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter)) です。

`scope` パラメーターにクレームグループを指定する方法は、柔軟性は高くありませんが簡単です。下表は、定義済みのクレームグループ名と、それを `scope` に含めたときにどのクレーム群が ID トークンに含まれることになるかを示したものです。

| グループ名 | グループに含まれるクレーム群 |
|:--|:--|
| `profile` | `name`, `family_name`, `given_name`, `middle_name`, `nickname`, `preferred_username`, `profile`, `picture`, `website`, `gender`, `birthdate`, `zoneinfo`, `locale`, `updated_at`  |
| `email` | `email`, `email_verified` |
| `address` | `address` |
| `phone` | `phone_number`, `phone_number_verified` |

一方、`claims` パラメーターを用いて要求する方法は、柔軟であり、カスタムクレームを要求するための唯一の方法ではありますが、`claims` パラメーターの使用方法は、思いのほか複雑です。単純にクレーム名を列挙すればいいわけではありません。詳細は [5.5. Requesting Claims using the "claims" Request Parameter](http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter) を参照してください。

なお、`claims` パラメーターのパース処理は複雑で、実装するにはそれなりに手間がかかります。そのためか、`claims` パラメーターをサポートするかどうかを示す属性として `claims_parameter_supported` が [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) の [3. OpenID Provier Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) で定義されており、デフォルト値は false となっています。


# **16. 認証コンテキストクラス**

**Authentication Context Class Reference** (以降 **ACR**) という語があり、これは、認証コンテキストクラスの識別子のことです。例えば「`urn:oasis:names:tc:SAML:2.0:ac:classes:Password`」という ACR はパスワードによる認証に与えられた識別子、「`urn:oasis:names:tc:SAML:2.0:ac:classes:X509`」という ACR は X.509 証明書による認証に与えられた識別子です。OpenID Connect では、この ACR に関係する仕様が幾つか定義されています。

### **16.1. acr_values リクエストパラメーター**

`acr_values` は、リクエスト時に指定することができる新しいパラメーターです ([3.1.2.1. Authentication Request](http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest))。このパラメーターの値に ACR のリストを指定することで、クライアントアプリケーションは、ユーザー認証時に満たして欲しい認証コンテキストクラスを指定することができます。

### **16.2 claims リクエストパラメーター内の acr クレーム**

リクエスト時に ACR のリストを指定する方法としては、`acr_values` リクエストパラメーターを用いる方法のほか、`claims` リクエストパラメーターに `acr` クレームを含める方法があります。下記は `claims` パラメーターに渡す JSON の例で、[5.5. Requesting Claims using the "claims" Request Parameter](http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter) から抜粋したものです。`urn:mace:incommon:iap:silver` という ACR が一つ指定されています。

```json
{
 "userinfo":
  {
   "given_name": {"essential": true},
   "nickname": null,
   "email": {"essential": true},
   "email_verified": {"essential": true},
   "picture": null,
   "http://example.info/claims/groups": null
  },
 "id_token":
  {
   "auth_time": {"essential": true},
   "acr": {"values": ["urn:mace:incommon:iap:silver"] }
  }
}
```

指定した ACR 群のどれか一つが必ず満たされることを要求したい場合、`acr` クレームを必須 (essential) とマークします。これは、次のように「`"essential":true`」を JSON に含めることでおこないます。

```json
{
  "id_token":
    {
      "acr":
        {
          "essential": true,
          "values": ["urn:mace:incommon:iap:silver"]
        }
    }
}
```

`acr` クレームが必須とマークされているにも関わらず、指定された認証コンテキストクラスのいずれも満たすことができなかった場合、認可エンドポイントはエラーを返します。詳細は [5.5.1.1. Requesting the "acr" Claim](http://openid.net/specs/openid-connect-core-1_0.html#acrSemantics) を参照してください。

### **16.3. ID トークン内の acr クレーム**

ID トークンに `acr` クレームが含まれていた場合、それはユーザー認証時に満たされた認証コンテキストクラスを示しています。詳細は [2. ID Token](http://openid.net/specs/openid-connect-core-1_0.html#IDToken) を参照してください。

### **16.4. サポートされる ACR (acr_values_supported)**

OpenID プロバイダーは、自身がサポートする認証コンテキストクラスのリストを、`acr_values_supported` の値として公開することができます。詳細は [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) の [3. OpenID Provider Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) を参照してください。

### **16.5. デフォルトの ACR (default_acr_values)**

クライアントアプリケーションは、認可リクエストに ACR のリストが含まれていない場合に使用するデフォルトの ACR リストを、`default_acr_values` の値として予め設定しておくことができます。詳細は、[OpenID Connect Dynamic Client Registration 1.0](http://openid.net/specs/openid-connect-registration-1_0.html) の [2. Client Metadata](http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata) を参照してください。

### **16.6. ACR 処理の流れ**

ここまでに挙げた ACR に関するパラメーター群を踏まえると、OpenID プロバイダー側でおこなう ACR に関する処理フローは次のようになります。

1. 認可エンドポイントへのリクエストに含まれる `acr_values` リクエストパラメーター、もしくは `claims` リクエストパラメーターで指定された JSON 内の `acr` パラメーターから、ACR リストを取り出す。(仕様では、`acr_values` と `claims` 内の `acr` のどちらが優先されるかは言及されていない。ちなみに **[Authlete](https://www.authlete.com/)** では `claims` の方を優先する。)<br/><br/>

2. 前の処理で ACR リストが得られなければ、クライアントの `default_acr_values` 属性から ACR リストを取り出す。<br/><br/>

3. ここまでの処理で ACR リストが得られていれば、個々の要素がサポート済みであるかどうかを、OpenID プロバイダー自身の `acr_values_supported` 属性と照らし合わせて確認する。<br/><br/>

4. ACR リストは、「クライアントアプリケーションが希望する好ましい順」に並んでいるので、先頭から順番に、どれか一つが成功するまで、指定された認証方法でユーザー認証を試みる。<br/><br/>

5. 指定された認証方法のいずれでも認証ができなかった場合、リクエストの `claims` リクエストパラメーターで `acr` が `essential=true` とマークされているかどうかを調べる。もしも、`essential=true` であれば、クライアントアプリケーションにエラー応答を返す。<br/><br/>

6. 指定された認証方法のいずれかでの認証が成功した場合は、生成する ID トークンに `acr` クレームを含める。



# **17. 認証後許容経過時間**

**Maximum Authentication Age** という語があり、これは、ユーザーが最後に認証された時点からの経過時間として許容する時間の最大値を指します。経過時間がこの値よりも大きい場合、当該ユーザーが既にログイン済みであったとしても、ID トークンの発行に際して再度認証処理が必要となります。

### **17.1. max_age リクエストパラメーター**

クライアントアプリケーションは、`max_age` パラメーターを使い、許容する経過時間の最大値を指定することができます ([3.1.2.1. Authentication Request](http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest))。

### **17.2. 認証後許容経過時間の最大値のデフォルト値**

クライアントアプリケーションは、リクエストに `max_age` パラメーターが含まれていない場合に使用するデフォルトの認証後許容経過時間の最大値を、`default_max_age` の値として予め設定しておくことができます。詳細は、[OpenID Connect Dynamic Client Registration 1.0](http://openid.net/specs/openid-connect-registration-1_0.html) の [2. Client Metadata](http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata) を参照してください。


# **18. 認証対象ユーザーの指定**

クライアントアプリケーションは、`claims` リクエストパラメーターに渡す JSON 内で `sub` クレームの値を指定することにより、認証対象のユーザーを指定することができます。下記は、一意識別子として `248289761001` という値を持つユーザーを指定する例です。

```json
{
  "id_token":
    {
      "sub": {"value": "248289761001"}
    }
}
```

`sub` クレームが指定されている場合、認証はそのユーザーに対して実行されます。もしもこの条件を満たせない場合、認可エンドポイントはエラーを返します。詳細は [3.1.2.2. Authentication Request Validation](http://openid.net/specs/openid-connect-core-1_0.html#AuthRequestValidation) を参照してください。


# **19. ログイン ID に関するヒント (login_hint)**

クライアントアプリケーションは、`login_hint` リクエストパラメーターを用いて、認可エンドポイントにおける認証で使用するログイン ID に関するヒントを、サーバーに伝えることができます ([3.1.2.1. Authentication Request](http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest))。例えば、ユーザーのメールアドレスを `login_hint` に渡すといったことが考えられます。`login_hint` で渡された値をどのように利用するかは、全く利用しないケースも含め、サーバー側の自由です。


# **20. ヒントとしての ID トークン (id_token_hint)**

クライアントアプリケーションは、過去に認可サーバーから発行された ID トークンを `id_token_hint` リクエストパラメーターの値として指定することで、認証対象ユーザーに関するヒントをサーバーに伝えることができます ([3.1.2.1. Authentication Request](http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest))。


# **21. プロンプト (prompt)**

認可エンドポイントにアクセスすると、認可処理に含まれる手順の一つとして、ユーザー認証処理が行われます。どのようにユーザー認証を行うかは実装依存であり、RFC 6749 では「この仕様の範囲外である」と明確に書いています (参考：[認証と認可](http://qiita.com/TakahikoKawasaki/items/f2a0d25a4f05790b3baa#%E8%AA%8D%E8%A8%BC%E3%81%A8%E8%AA%8D%E5%8F%AF))。そのため、認可サーバーによっては、既にユーザーがログイン済みである場合、認証処理を省略することがあります。加えて、既にユーザーが対象となるクライアントアプリケーションに対して過去に認可を与えていれば、同意の確認さえ省略することがあります。

このような実装依存の動作に対し、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) では `prompt` というリクエストパラメーターを追加し、クライアントアプリケーション側から動作を制御できるようにしました ([3.1.2.1. Authentication Request](http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest))。

`prompt` が取りうる値は、`login`, `consent`, `select_account` の任意の組み合わせか、もしくは `none` です。それぞれ次のような意味があります。

| 値 | 意味 |
|----|-----|
| `none`           | ユーザー認証や同意のための画面を一切出さない。 |
| `login`          | 過去に認証済みでも、ユーザー認証をおこなう。 |
| `consent`        | 過去に同意取得済みでも、同意確認をおこなう。 |
| `select_account` | 複数のユーザーアカウントの中から選択できるようにする。 |

 `prompt=none` の場合、認証と同意が事前に済んでいる場合に限り、リクエストが成功します。


# **22. 表示モード (display)**

認可エンドポイントにアクセスすると、リクエストに `prompt=none` が含まれない限り、認可画面が表示されますが、この画面の表示モードを制御するリクエストパラメーターとして `display` が定義されています ([3.1.2.1. Authentication Request](http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest))。`display` が取りうる値は次の 4 つで、`display` パラメーターが省略された場合は `page` が指定されたものとして処理されます。

| 値 | 意味 |
|----|-----|
| `page`  | ブラウザの描画領域全体を使って表示をおこなう。 |
| `popup` | ポップアップ形式で表示をおこなう。|
| `touch` | タッチスクリーン向けの表示をおこなう。 |
| `wap`   | フィーチャーフォン向けの表示をおこなう。 |

OpenID プロバイダーは、自身がサポートする表示モードのリストを、`display_values_supported` の値として公開することができます。詳細は [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) の [3. OpenID Provider Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) を参照してください。


# **23. 表示言語 (ui_locales)**

認可画面で使われる言語を `ui_locales` リクエストパラメーターで指定することができます。`ui_locales` には、希望する順番で**言語タグ**をスペース区切で列挙します。言語タグの形式は、**[RFC 5646](https://tools.ietf.org/html/rfc5646)** (Tags for Identifying Languages) で定義されています。

例えば、`ui_locales` の値が `fr-CA fr en` であれば、これは、「カナダで使用されているフランス語、フランス語、英語」、という意味になります。

OpenID プロバイダーは、自身がサポートする表示言語のリストを、`ui_locales_supported` の値として公開することができます。詳細は [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) の [3. OpenID Provider Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) を参照してください。


# **24. リクエストオブジェクト**

認可エンドポイントに渡すリクエストパラメーター群を [JWT](https://tools.ietf.org/html/rfc7519) 形式で渡す方法が [OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の「[6. Passing Request Parameters as JWTs](http://openid.net/specs/openid-connect-core-1_0.html#JWTRequests)」で定義されています。仕様では、リクエストパラメーター群を含む JWT を**リクエストオブジェクト**と呼んでいます。

リクエストオブジェクトを指定する方法には、次の二つがあります。

1. `request` パラメーターでリクエストオブジェクトの値を直接渡す方法 ([6.1. Passing a Request Object by Value](http://openid.net/specs/openid-connect-core-1_0.html#RequestObject))
2. `request_uri` パラメーターでリクエストオブジェクトの場所を伝える方法 ([6.2. Passing a Request Object by Reference](http://openid.net/specs/openid-connect-core-1_0.html#RequestUriParameter))

OpenID プロバイダーは、これらの方法をサポートするかどうかを、Discovery 情報に次の項目を含めることで公開できます。

| 項目 | デフォルト値 | 説明 |
|---|---|---|
| `request_parameter_supported` | `false` | `request` パラメーターをサポートするかどうか |
| `request_uri_parameter_supported` | `false` | `request_uri` パラメーターをサポートするかどうか |

同様にして、OpenID プロバイダーがサポートするリクエストオブジェクトの署名・暗号アルゴリズムのリストは、次の項目で示されます。

* `request_object_signing_alg_values_supported`
* `request_object_encryption_alg_values_supported`
* `request_object_encryption_enc_values_supported`

これらのメタ情報の詳細については [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) の [3. OpenID Provider Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) を参照してください。


# **25. その他**

必要に応じて追記していきます。


# **関連仕様リスト**

- [OAuth Core 1.0](http://oauth.net/core/1.0/)
- [OAuth Core 1.0 Revision A](http://oauth.net/core/1.0a/)
- [RFC 5646](https://tools.ietf.org/html/rfc5646): Tags for Identifying Languages
- [RFC 5849](https://tools.ietf.org/html/rfc5849): The OAuth 1.0 Protocol (Obsoleted by [RFC 6749](https://tools.ietf.org/html/rfc6749))
- [RFC 6749](https://tools.ietf.org/html/rfc6749): The OAuth 2.0 Authorization Framework
- [RFC 6750](https://tools.ietf.org/html/rfc6750): The OAuth 2.0 Authorization Framework: Bearer Token Usage
- [RFC 6819](https://tools.ietf.org/html/rfc6819): OAuth 2.0 Threat Model and Security Considerations
- [RFC 7009](https://tools.ietf.org/html/rfc7009): OAuth 2.0 Token Revocation
- [RFC 7033](https://tools.ietf.org/html/rfc7033): WebFinger
- [RFC 7515](https://tools.ietf.org/html/rfc7515): JSON Web Signature (JWS)
- [RFC 7516](https://tools.ietf.org/html/rfc7516): JSON Web Encryption (JWE)
- [RFC 7517](https://tools.ietf.org/html/rfc7517): JSON Web Key (JWK)
- [RFC 7518](https://tools.ietf.org/html/rfc7518): JSON Web Algorithms (JWA)
- [RFC 7519](https://tools.ietf.org/html/rfc7519): JSON Web Token (JWT)
- [RFC 7521](https://tools.ietf.org/html/rfc7521): Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants
- [RFC 7522](https://tools.ietf.org/html/rfc7522): Security Assertion Markup Language (SAML) 2.0 Profile for OAuth 2.0 Client Authentication and Authorization Grants
- [RFC 7523](https://tools.ietf.org/html/rfc7523): JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants
- [RFC 7636](https://tools.ietf.org/html/rfc7636): Proof Key for Code Exchange by OAuth Public Clients
- [RFC 7662](https://tools.ietf.org/html/rfc7662): OAuth 2.0 Token Introspection
- [RFC 8252](https://tools.ietf.org/html/rfc8252): OAuth 2.0 for Native Apps
- OAuth 2.0 [Multiple Response Type Encoding Practices](http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html)
- OAuth 2.0 [Form Post Response Mode](http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html)
- OAuth 2.0 [Authorization Server Discovery Metadata](https://tools.ietf.org/html/draft-jones-oauth-discovery) (Draft)
- OpenID Connect [Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html)
- OpenID Connect [Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html)
- OpenID Connect [Dynamic Client Registration 1.0](http://openid.net/specs/openid-connect-registration-1_0.html)
- OpenID Connect [Session Management 1.0](http://openid.net/specs/openid-connect-session-1_0.html)
- OpenID Connect [Front-Channel Logout 1.0](http://openid.net/specs/openid-connect-frontchannel-1_0.html) (Draft)
- OpenID Connect [Back-Channel Logout 1.0](http://openid.net/specs/openid-connect-backchannel-1_0.html) (Draft)


<sup>注意：全ての関連仕様を網羅しているわけではありません。</sup>


# おわりに

こちらも併せてご覧いただければと思います。

* [OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る](http://qiita.com/TakahikoKawasaki/items/f2a0d25a4f05790b3baa)
* [【第二弾】OAuth 2.0 + OpenID Connect のフルスクラッチ実装者が知見を語る](http://qiita.com/TakahikoKawasaki/items/30fbd546935cea914e4f)
* [OAuth 1.0 のほうが OAuth 2.0 より安全なの？](http://qiita.com/TakahikoKawasaki/items/3600b28af7b63671b968)
* [OAuth & OpenID Connect の不適切実装まとめ](http://qiita.com/TakahikoKawasaki/items/efbbd2c5875577c911a3)
* [Amazon API Gateway の Custom Authorizer を使い、OAuth アクセストークンで API を保護する](http://qiita.com/TakahikoKawasaki/items/b372ab49da0a9aedb76a)
* [Proof Key for Code Exchange (RFC 7636)](https://www.authlete.com/documents/article/pkce)