IDトークンが分かれば OpenID Connect が分かる

# **はじめに**

**「解説記事を幾つも読んだけど OpenID Connect を理解できた気がしない」**― この文書は、そういう悩みを抱えたエンジニアの方々に向けた **[OpenID Connect](http://openid.net/connect/)** 解説文書です。概念的・抽象的な話を避け、具体例を用いて OpenID Connect を解説していこうと思います。

この文書では、**JWS** ([RFC 7515](https://tools.ietf.org/html/rfc7515))、**JWE** ([RFC 7516](https://tools.ietf.org/html/rfc7516))、**JWK** ([RFC 7517](https://tools.ietf.org/html/rfc7517))、**JWT** ([RFC 7519](https://tools.ietf.org/html/rfc7519))、**ID トークン**の説明をおこないます。

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


# **1. 『ID トークン』を発行するための仕様**

一般の方々に対しては「OpenID Connect は認証の仕様である」という説明で良いと思います。一方、技術的な理解を渇望しているエンジニアの方々に対しては、**「OpenID Connect は『ID トークン』を発行するための仕様である」**という割り切り方を勧めたほうが良いと考えています。というわけで、まず、**ID トークン**について説明しようと思います。


# **2. ID トークンの外観**

一般の方々に対しては「ID トークンは認証の結果得られるトークンである」という説明で良いと思います。一方、エンジニアの方々には、「ID トークンは具体的にはこんな感じの文字列データです」と言って、まず具体例を見ていただくのが良いと考えています。そういうわけで、早速ですが、OpenID Connect の中心となる仕様書「**[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html)**」の「[A.2.  Example using response_type=id_token](http://openid.net/specs/openid-connect-core-1_0.html#id_tokenExample)」から抜粋した ID トークンの例を掲載します。なお、この ID トークンの例には改行が含まれていますが、本来は ID トークンの中に改行は含まれません。ここでは単に見やすいように改行を入れているだけです。

```
eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlz
cyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4
Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAi
bi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEz
MTEyODA5NzAsCiAibmFtZSI6ICJKYW5lIERvZSIsCiAiZ2l2ZW5fbmFtZSI6
ICJKYW5lIiwKICJmYW1pbHlfbmFtZSI6ICJEb2UiLAogImdlbmRlciI6ICJm
ZW1hbGUiLAogImJpcnRoZGF0ZSI6ICIwMDAwLTEwLTMxIiwKICJlbWFpbCI6
ICJqYW5lZG9lQGV4YW1wbGUuY29tIiwKICJwaWN0dXJlIjogImh0dHA6Ly9l
eGFtcGxlLmNvbS9qYW5lZG9lL21lLmpwZyIKfQ.rHQjEmBqn9Jre0OLykYNn
spA10Qql2rvx4FsD00jwlB0Sym4NzpgvPKsDjn_wMkHxcp6CilPcoKrWHcip
R2iAjzLvDNAReF97zoJqq880ZD1bwY82JDauCXELVR9O6_B0w3K-E7yM2mac
AAgNCUwtik6SjoSUZRcf-O5lygIyLENx882p6MtmwaL1hd6qn5RZOQ0TLrOY
u0532g9Exxcm-ChymrB4xLykpDj3lUivJt63eEGGN6DH5K6o33TcxkIjNrCD
4XB1CKKumZvCedgHHF3IAK4dVEDSUoGlH9z4pP_eWYNXvqQOjGs-rDaQzUHl
6cQQWNiDpWOl_lxXjQEvQ
```

この ID トークンの例の中には、ピリオドが二つ含まれています。一つ目は一行目の右から 9 文字目に、二つ目は九行目の右から 22 文字目にあります。この二つのピリオドにより、ID トークンは三つの部分に分けられます。 (三つにならないケースについては後述します。)

三つの部分は、先頭から順に、ヘッダー、ペイロード (本文)、署名、を表しています。つまり、ID トークンは形式的には次のような形になっています。

```
ヘッダー.ペイロード.署名
```

前掲の ID トークンの場合、ヘッダー、ペイロード、署名の値を別々に切り出すと、次のようになります。

```
# ヘッダー
eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ
```

```
# ペイロード
ewogImlz
cyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4
Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAi
bi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEz
MTEyODA5NzAsCiAibmFtZSI6ICJKYW5lIERvZSIsCiAiZ2l2ZW5fbmFtZSI6
ICJKYW5lIiwKICJmYW1pbHlfbmFtZSI6ICJEb2UiLAogImdlbmRlciI6ICJm
ZW1hbGUiLAogImJpcnRoZGF0ZSI6ICIwMDAwLTEwLTMxIiwKICJlbWFpbCI6
ICJqYW5lZG9lQGV4YW1wbGUuY29tIiwKICJwaWN0dXJlIjogImh0dHA6Ly9l
eGFtcGxlLmNvbS9qYW5lZG9lL21lLmpwZyIKfQ
```

```
# 署名
rHQjEmBqn9Jre0OLykYNn
spA10Qql2rvx4FsD00jwlB0Sym4NzpgvPKsDjn_wMkHxcp6CilPcoKrWHcip
R2iAjzLvDNAReF97zoJqq880ZD1bwY82JDauCXELVR9O6_B0w3K-E7yM2mac
AAgNCUwtik6SjoSUZRcf-O5lygIyLENx882p6MtmwaL1hd6qn5RZOQ0TLrOY
u0532g9Exxcm-ChymrB4xLykpDj3lUivJt63eEGGN6DH5K6o33TcxkIjNrCD
4XB1CKKumZvCedgHHF3IAK4dVEDSUoGlH9z4pP_eWYNXvqQOjGs-rDaQzUHl
6cQQWNiDpWOl_lxXjQEvQ
```


# **3. JSON Web Signature (JWS)**

前節で紹介した「ヘッダー.ペイロード.署名」という形式は、実は **[RFC 7515](https://tools.ietf.org/html/rfc7515)** (**JSON Web Signature** (**JWS**)) の「[7.1. JWS Compact Serialization](https://tools.ietf.org/html/rfc7515#section-7.1)」で定義されている「JSON Web Signature (JWS) の Compact Serialization 形式」です。具体的には次のように定義されています。 <sup>([RFC 7515](https://tools.ietf.org/html/rfc7515) は [JSON Serialization](https://tools.ietf.org/html/rfc7515#section-7.2) 形式も定義していますが、ここでは扱いません。)</sup>

```
BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)
```

この定義を見ると、三つの部分はそれぞれ、元のデータを **base64url** ([RFC 4648, 5. Base 64 Encoding with URL and Filename Safe Alphabet](https://tools.ietf.org/html/rfc4648#section-5)) でエンコードしたものだということが分かります。ということは、base64url でデコードすると、元のデータが得られます。早速やってみましょう。

### **3.1. JWS ヘッダーのデコード**

まず、ヘッダー部をデコードしてみます。ここでは、[base64-url-cli](https://www.npmjs.com/package/base64-url-cli) をインストールし、コマンドラインでデコードをおこないます。

```
$ npm install -g base64-url-cli
$ base64url decode eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ
```

結果、次のような JSON が得られます。

```json
{"kid":"1e9gdk7","alg":"RS256"}
```

この JSON には、`kid` と `alg` という二つのパラメーターが含まれています。これらに加え、その他の有効なパラメーターは [RFC 7515](https://tools.ietf.org/html/rfc7515) の「[4.1. Registered Header Parameter Names](https://tools.ietf.org/html/rfc7515#section-4.1)」に列挙されています。

| パラメーター名 | 説明 |
|:-:|:--|
| <code>[alg](https://tools.ietf.org/html/rfc7515#section-4.1.1)</code> | アルゴリズム |
| <code>[jku](https://tools.ietf.org/html/rfc7515#section-4.1.2)</code> | JWK セット URL |
| <code>[jwk](https://tools.ietf.org/html/rfc7515#section-4.1.3)</code> | JSON Web キー |
| <code>[kid](https://tools.ietf.org/html/rfc7515#section-4.1.4)</code> | キー ID |
| <code>[x5u](https://tools.ietf.org/html/rfc7515#section-4.1.5)</code> | X.509 URL |
| <code>[x5c](https://tools.ietf.org/html/rfc7515#section-4.1.6)</code> | X.509 証明書チェーン |
| <code>[x5t](https://tools.ietf.org/html/rfc7515#section-4.1.7)</code> | X.509 証明書 SHA-1 Thumbprint |
| <code>[x5t#S256](https://tools.ietf.org/html/rfc7515#section-4.1.8)</code> | X.509 証明書 SHA-256 Thumbprint |
| <code>[typ](https://tools.ietf.org/html/rfc7515#section-4.1.9)</code> | JWS 自身のメディアタイプ |
| <code>[cty](https://tools.ietf.org/html/rfc7515#section-4.1.10)</code> | ペイロードのメディアタイプ |
| <code>[crit](https://tools.ietf.org/html/rfc7515#section-4.1.11)</code> | 必須パラメーター群指定 |

これらのうち、`alg` は署名で使用するアルゴリズムを指定するものです。署名については後述します。


### **3.2. JWS ペイロードのデコード**

同様にして、ペイロードを base64url でデコードすると、

```
$ base64url decode ewogImlzcy{中略}LmpwZyIKfQ
```

次の JSON が得られます。

```json
{
 "iss": "http://server.example.com",
 "sub": "248289761001",
 "aud": "s6BhdRkqt3",
 "nonce": "n-0S6_WzA2Mj",
 "exp": 1311281970,
 "iat": 1311280970,
 "name": "Jane Doe",
 "given_name": "Jane",
 "family_name": "Doe",
 "gender": "female",
 "birthdate": "0000-10-31",
 "email": "janedoe@example.com",
 "picture": "http://example.com/janedoe/me.jpg"
}
```

この内容については、のちほど詳述します。なお、この例では、ペイロード部分の元データが上記のように JSON となっていますが、[RFC 7515](https://tools.ietf.org/html/rfc7515) 自体は JSON を要求しておらず、任意のデータ (an arbitrary sequence of octets) で構わないとしています。


### **3.3. JWS 署名のデコード**

ヘッダーに含まれている `alg` パラメーターの値は、署名のアルゴリズムを示しています。`alg` の値として有効な値は、[RFC 7515](https://tools.ietf.org/html/rfc7515) ではなく、別仕様書 **[RFC 7518](https://tools.ietf.org/html/rfc7518)** (**JSON Web Algorithms** (**JWA**)) の「[3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1)」に列挙されています。

| `alg` の値 | アルゴリズム |
|:-:|:--|
| `HS256` | HMAC using SHA-256                             |
| `HS384` | HMAC using SHA-384                             |
| `HS512` | HMAC using SHA-512                             |
| `RS256` | RSASSA-PKCS1-v1_5 using SHA-256                |
| `RS384` | RSASSA-PKCS1-v1_5 using SHA-384                |
| `RS512` | RSASSA-PKCS1-v1_5 using SHA-512                |
| `ES256` | ECDSA using P-256 and SHA-256                  |
| `ES384` | ECDSA using P-384 and SHA-384                  |
| `ES512` | ECDSA using P-521 and SHA-512                  |
| `PS256` | RSASSA-PSS using SHA-256 and MGF1 with SHA-256 |
| `PS384` | RSASSA-PSS using SHA-384 and MGF1 with SHA-384 |
| `PS512` | RSASSA-PSS using SHA-512 and MGF1 with SHA-512 |
| `none`  | No digital signature or MAC performed          |

「3.1. JWS ヘッダーのデコード」の結果、`alg` の値は `RS256` だということが分かっています。「[3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1)」の表と照合すると、`RS256` は「RSASSA-PKCS1-v1_5 using SHA-256」を示していますので、RSA アルゴリズムによる署名ということが分かります。

RSA の署名はバイナリデータなので、base64url でデコードするとバイナリデータが得られます (ヘッダーやペイロードのように JSON は得られません)。署名部分を base64url デコードし、続けて 10 進数表記すると、次のようになります。(見ても意味は分かりませんが。)

```
$ base64url decode rHQjEmBqn9{中略}l_lxXjQEvQ | od -tu1 -An
 239 191 189 116  35  18  96 106 239 191 189 239 191 189 107 123
  67 239 191 189 239 191 189  70  13 239 191 189 239 191 189  64
 239 191 189  68  42 239 191 189 106 239 191 189 199 129 108  15
  77  35 239 191 189  80 116  75  41 239 191 189  55  58  96 239
 191 189 239 191 189 239 191 189  14  57 239 191 189 239 191 189
 239 191 189   7 239 191 189 239 191 189 122  10  41  79 114 239
 191 189 239 191 189  88 119  34 239 191 189  29 239 191 189   2
  60 203 188  51  64  69 239 191 189 125 239 191 189  58   9 239
 191 189 239 191 189  60 209 144 239 191 189 111   6  60 216 144
 218 184  37 239 191 189  45  84 125  59 239 191 189 239 191 189
 239 191 189  13 239 191 189 239 191 189  78 239 191 189  51 105
 239 191 189 112   0  32  52  37  48 239 191 189  41  58  74  58
  18  81 239 191 189  92 127 227 185 151  40   8 200 177  13 239
 191 189 239 191 189  54 239 191 189 239 191 189  45 239 191 189
   6 239 191 189 239 191 189  23 122 239 191 189 126  81 100 239
 191 189  52  76 239 191 189 239 191 189  98 239 191 189  57 239
 191 189 104  61  19  28  92 239 191 189 239 191 189 239 191 189
 239 191 189 106 239 191 189 239 191 189  18 239 191 189 239 191
 189 239 191 189 239 191 189 239 191 189  85  34 239 191 189 239
 191 189 122 239 191 189 239 191 189   6  24 222 131  31 239 191
 189 239 191 189 239 191 189 125 239 191 189 115  25   8 239 191
 189 239 191 189 239 191 189  15 239 191 189 239 191 189 239 191
 189  34 239 191 189 239 191 189 102 111   9 239 191 189  96  28
 113 119  32   2 239 191 189 117  81   3  73  74   6 239 191 189
 127 115 239 191 189 239 191 189 239 191 189 121 102  13  94 239
 191 189 239 191 189  58  49 239 191 189 239 191 189 239 191 189
 239 191 189  67  53   7 239 191 189 239 191 189  16  65  99  98
  14 239 191 189 239 191 189 239 191 189 239 191 189 113  94  52
   4 239 191 189  10
```

### **3.4. JWS 署名の対象**

そもそも何に対する署名なのか、という話が最後になってしまいました。署名処理に対する入力データは、「ヘッダー.ペイロード」です。これまでの例でいうと、次のデータが署名に対する入力データとなります。

```
eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlz
cyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4
Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAi
bi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEz
MTEyODA5NzAsCiAibmFtZSI6ICJKYW5lIERvZSIsCiAiZ2l2ZW5fbmFtZSI6
ICJKYW5lIiwKICJmYW1pbHlfbmFtZSI6ICJEb2UiLAogImdlbmRlciI6ICJm
ZW1hbGUiLAogImJpcnRoZGF0ZSI6ICIwMDAwLTEwLTMxIiwKICJlbWFpbCI6
ICJqYW5lZG9lQGV4YW1wbGUuY29tIiwKICJwaWN0dXJlIjogImh0dHA6Ly9l
eGFtcGxlLmNvbS9qYW5lZG9lL21lLmpwZyIKfQ
```

### **3.5. JWS デコードのまとめ**

ID トークンは Compact Serialization 形式で表現されているため、下記に再掲するように、そのままでは表現している情報の内容が分かりません。

```
eyJraWQiOiIxZTlnZGs3IiwiYWxnIjoiUlMyNTYifQ.ewogImlz
cyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4
Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAi
bi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEz
MTEyODA5NzAsCiAibmFtZSI6ICJKYW5lIERvZSIsCiAiZ2l2ZW5fbmFtZSI6
ICJKYW5lIiwKICJmYW1pbHlfbmFtZSI6ICJEb2UiLAogImdlbmRlciI6ICJm
ZW1hbGUiLAogImJpcnRoZGF0ZSI6ICIwMDAwLTEwLTMxIiwKICJlbWFpbCI6
ICJqYW5lZG9lQGV4YW1wbGUuY29tIiwKICJwaWN0dXJlIjogImh0dHA6Ly9l
eGFtcGxlLmNvbS9qYW5lZG9lL21lLmpwZyIKfQ.rHQjEmBqn9Jre0OLykYNn
spA10Qql2rvx4FsD00jwlB0Sym4NzpgvPKsDjn_wMkHxcp6CilPcoKrWHcip
R2iAjzLvDNAReF97zoJqq880ZD1bwY82JDauCXELVR9O6_B0w3K-E7yM2mac
AAgNCUwtik6SjoSUZRcf-O5lygIyLENx882p6MtmwaL1hd6qn5RZOQ0TLrOY
u0532g9Exxcm-ChymrB4xLykpDj3lUivJt63eEGGN6DH5K6o33TcxkIjNrCD
4XB1CKKumZvCedgHHF3IAK4dVEDSUoGlH9z4pP_eWYNXvqQOjGs-rDaQzUHl
6cQQWNiDpWOl_lxXjQEvQ
```

しかし、[RFC 7515](https://tools.ietf.org/html/rfc7515) の情報をもとに base64url デコードしていくことにより、上記の無味乾燥な文字列は、次の情報を持っていることが分かりました。

```json
{"kid":"1e9gdk7","alg":"RS256"}
```
```json
{
 "iss": "http://server.example.com",
 "sub": "248289761001",
 "aud": "s6BhdRkqt3",
 "nonce": "n-0S6_WzA2Mj",
 "exp": 1311281970,
 "iat": 1311280970,
 "name": "Jane Doe",
 "given_name": "Jane",
 "family_name": "Doe",
 "gender": "female",
 "birthdate": "0000-10-31",
 "email": "janedoe@example.com",
 "picture": "http://example.com/janedoe/me.jpg"
}
```
```
署名
```

ここまでの話で、ID トークンとは何かを具体的にイメージできるようになったのではないでしょうか。


### **3.6. Unsecured JWS**

せっかくですので、**Unsecured JWS** を紹介します。Unsecured JWS は、署名の無い JWS です。下記は、[RFC 7515](https://tools.ietf.org/html/rfc7515) の [A.5. Example Unsecured JWS](https://tools.ietf.org/html/rfc7515#appendix-A.5) から抜粋した Unsecured JWS の例です。

```
eyJhbGciOiJub25lIn0
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
```

Unsecured JWS は次のような形式となっており、JWS 内の三番目のフィールドが空になっています。

```
ヘッダー.ペイロード.
```

署名が無いということは、署名アルゴリズムも無いので、JWS ヘッダーの `alg` には `none` を指定することになっています。上記例の JWS ヘッダー部分である `eyJhbGciOiJub25lIn0` を base64url でデコードすると、

```
$ base64url decode eyJhbGciOiJub25lIn0
```

次のような JSON が得られます。

```json
{"alg":"none"}
```

確かに `alg` が `none` になっていることが分かります。


# **4. JSON Web Encryption (JWE)**

さて、ID トークンの形式には、これまで説明してきた「ヘッダー.ペイロード.署名」の他に、次のように 5 つのフィールドを持つ形式もあります。

```
ヘッダー.キー.初期ベクター.暗号文.認証タグ
```

この形式は、**[RFC 7516](https://tools.ietf.org/html/rfc7516)** (**JSON Web Encryption** (**JWE**)) の「[7.1. JWE Compact Serialization](https://tools.ietf.org/html/rfc7516#section-7.1)」で定義されている「JSON Web Encryption (JWE) の Compact Serialization 形式」です。具体的には次のように定義されています。 <sup>([RFC 7516](https://tools.ietf.org/html/rfc7516) は [JSON Serialization](https://tools.ietf.org/html/rfc7516#section-7.2) 形式も定義していますが、ここでは扱いません。)</sup>

```
BASE64URL(UTF8(JWE Protected Header)) || '.' ||
BASE64URL(JWE Encrypted Key) || '.' ||
BASE64URL(JWE Initialization Vector) || '.' ||
BASE64URL(JWE Ciphertext) || '.' ||
BASE64URL(JWE Authentication Tag)
```

この形式は、ID トークンを暗号化したいときに利用されます。

暗号化の対象となる平文は、暗号化されたあと、4 番目のフィールドに置かれます。[RFC 7516](https://tools.ietf.org/html/rfc7516) 自体は平文の内容は何でもよいとしていますが、ID トークンの文脈では、平文は「ヘッダー.ペイロード.署名」となります。つまり、JWE の中に JWS が入っている形になります。


### **4.1. 二段階の暗号処理**

「[7.1. JWE Compact Serialization](https://tools.ietf.org/html/rfc7516#section-7.1)」によれば、Compact Serialization 形式の 2 番目のフィールドは「JWE Encrypted Key」となっています。Encryption ではなく Encrypted となっているので、日本語に訳すとすれば、「暗号キー」ではなく「暗号化されたキー」となります。このような表現になっているのには理由があります。

JWE に限った話ではありませんが、特に非対称鍵系暗号を用いる場合、暗号が次のような二段階で行われることがあります。

1. 対称鍵系暗号の共有鍵を用いて、平文を暗号化する。
2. 上記の暗号処理に用いた共有鍵自体を、別の非対称鍵系暗号の鍵を用いて暗号化する。

二段階にすることで、平文の暗号化に対称鍵系暗号を用いて暗号化・復号化にかかる時間を抑えつつ、非対称鍵系暗号の利点を得ることができます。なお、ここで用いる対称鍵系暗号の共有鍵は、事前に共有しておく必要はなく、暗号処理をおこなう側が暗号処理実行時にランダムに生成することができます。というのは、ランダムに生成しても、その共有鍵を非対称鍵系暗号の鍵で暗号化して相手側に渡せば、相手側は、その暗号化された共有鍵を非対称鍵系暗号の鍵で復号化することで、当該共有鍵を取り出せるからです。

下図は、二段階の暗号処理を図にしたものです。JWE Encrypted Key は図中の「暗号化された共有鍵」に相当します。

![二段階の暗号処理.png](https://qiita-image-store.s3.amazonaws.com/0/106044/a9c7170f-ab6c-1692-388b-499b6d57007e.png)


### **4.2. 暗号アルゴリズム**

JWE では二段階の暗号処理をおこなっています。それぞれに暗号アルゴリズムがありますので、JWE には二つの暗号アルゴリズムが関わることになります。

平文を暗号文へと暗号化するときに使用するアルゴリズムは、[RFC 7518](https://tools.ietf.org/html/rfc7518) (JSON Web Algorithms) の「[5.1. "enc" (Encryption Algorithm) Header Parameter Values for JWE](https://tools.ietf.org/html/rfc7518#section-5.1)」に次のようにリストアップされています。

| `enc` の値 | アルゴリズム |
|:--|:--|
| `A128CBC-HS256` | AES using 128-bit IV and SHA-256 |
| `A192CBC-HS384` | AES using 192-bit IV and SHA-384 |
| `A256CBC-HS512` | AES using 256-bit IV and SHA-512 |
| `A128GCM`       | AES GCM using 128-bit key |
| `A192GCM`       | AES GCM using 192-bit key |
| `A256GCM`       | AES GCM using 256-bit key |

一方、共有鍵を暗号化するときに使用するアルゴリズムは「[4.1. "alg" (Algorithm) Header Parameter Values for JWE](https://tools.ietf.org/html/rfc7518#section-4.1)」に次のようにリストアップされています。

| `alg` の値            | アルゴリズム |
|:---------------------|:--|
| `RSA1_5`             | RSAES-PKCS1-v1_5 |
| `RSA-OAEP`           | RSAES OAEP using default parameters |
| `RSA-OAEP-256`       | RSAES OAEP using SHA-256 and MGF1 with SHA-256 |
| `A128KW`             | AES Key Wrap with default initial value using 128-bit key |
| `A192KW`             | AES Key Wrap with default initial value using 192-bit key |
| `A256KW`             | AES Key Wrap with default initial value using 256-bit key |
| `dir`                | Direct use of a shared symmetric key as the CEK |
| `ECDH-ES`            | Elliptic Curve Diffie-Hellman Ephemeral Static key agreement using Concat KDF |
| `ECDH-ES+A128KW`     | ECDH-ES using Concat KDF and CEK wrapped with "A128KW" |
| `ECDH-ES+A192KW`     | ECDH-ES using Concat KDF and CEK wrapped with "A192KW" |
| `ECDH-ES+A256KW`     | ECDH-ES using Concat KDF and CEK wrapped with "A256KW" |
| `A128GCMKW`          | Key wrapping with AES GCM using 128-bit key |
| `A192GCMKW`          | Key wrapping with AES GCM using 192-bit key |
| `A256GCMKW`          | Key wrapping with AES GCM using 256-bit key |
| `PBES2-HS256+A128KW` | PBES2 with HMAC SHA-256 and "A128KW" wrapping |
| `PBES2-HS384+A192KW` | PBES2 with HMAC SHA-384 and "A192KW" wrapping |
| `PBES2-HS512+A256KW` | PBES2 with HMAC SHA-512 and "A256KW" wrapping |



### **4.3. 共有鍵を暗号化するアルゴリズム `dir`**

前節に挙げた「共有鍵を暗号化するアルゴリズム」の識別子のうち、`dir` は特殊です。というのは、[RFC 7518](https://tools.ietf.org/html/rfc7518) の「[4.5. Direct Encryption with a Shared Symmetric Key](https://tools.ietf.org/html/rfc7518#section-4.5)」に次のように書かれているように、`dir` は、二段階暗号方式ではなく直接共有鍵暗号処理をおこなう方式だからです。

> This section defines the specifics of **directly performing symmetric key encryption** without performing a key wrapping step.

[RFC 7518](https://tools.ietf.org/html/rfc7518) では、共有鍵の決め方について特にルールは定めていません。一方、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の「[10.2. Encryption](http://openid.net/specs/openid-connect-core-1_0.html#Encryption)」では、対称鍵系暗号使用時のキーに対する要求事項を次のように定めています。

> **Symmetric Encryption**
> The symmetric encryption key is derived from the `client_secret` value by using **a left truncated SHA-2 hash of the octets of the UTF-8 representation of the `client_secret`**. For keys of 256 or fewer bits, SHA-256 is used; for keys of 257-384 bits, SHA-384 is used; for keys of 385-512 bits, SHA-512 is used. The hash value MUST be left truncated to the appropriate bit length for the AES key wrapping or direct encryption algorithm used, for instance, truncating the SHA-256 hash to 128 bits for `A128KW`. If a symmetric key with greater than 512 bits is needed, a different method of deriving the key from the client_secret would have to be defined by an extension. Symmetric encryption MUST NOT be used by public (non-confidential) Clients because of their inability to keep secrets.

つまり、「クライアントシークレットを UTF-8 で表現し、SHA-2 系のアルゴリズムでハッシュ値を求め、適切な長さで切り詰めたものを、キーとして用いる」というルールを定めています。


### **4.4. JWE の例**

次のものは、[RFC 7516](https://tools.ietf.org/html/rfc7516) の「[A.1.7. Complete Representation](https://tools.ietf.org/html/rfc7516#appendix-A.1.7)」から抜粋した JWE の例です。途中改行が含まれていますが、見やすいように入れているだけであり、実際の JWE には改行は含まれません。なお、この JWE は ID トークンではありません。暗号化前の平文は「The true sign of intelligence is not knowledge but imagination.」という文字列です。

```
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.
OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe
ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb
Sv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaV
mqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je8
1860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi
6UklfCpIMfIjf7iGdXKHzg.
48V1_ALb6US04U3b.
5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji
SdiwkIr3ajwQzaBtQD_A.
XFBoMYUZodetZdvTiFvSkQ
```


### **4.5. JWE ヘッダーのデコード**

JWE 内のピリオドで区切られた 5 つのフィールドのうち、一番目のフィールドは JWE ヘッダーです。base64url でエンコードされてはいますが暗号化はされていないので、前節で挙げた JWE の例のヘッダー部分を base64url でデコードしてみましょう。

```
$ base64url decode eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ
```

結果、次のような JSON が得られます。

```json
{"alg":"RSA-OAEP","enc":"A256GCM"}
```

ここで、`alg` は共有鍵を暗号化する際のアルゴリズム、`enc` は平文を暗号化する際のアルゴリズムを示しています。それぞれの有効な値は、「4.2. 暗号アルゴリズム」に挙げたとおりです。

`alg` と `enc` を含め、JWE ヘッダーで指定可能なパラメーターは、[RFC 7516](https://tools.ietf.org/html/rfc7516) の「[4.1. Registered Header Parameter Names](https://tools.ietf.org/html/rfc7516#section-4.1)」に列挙されています。


| パラメーター名 | 説明 |
|:-:|:--|
| <code>[alg](https://tools.ietf.org/html/rfc7516#section-4.1.1)</code> | 共有鍵を暗号化するアルゴリズム |
| <code>[enc](https://tools.ietf.org/html/rfc7516#section-4.1.2)        | 平文を暗号化するアルゴリズム |
| <code>[zip](https://tools.ietf.org/html/rfc7516#section-4.1.3)        | 圧縮アルゴリズム |
| <code>[jku](https://tools.ietf.org/html/rfc7516#section-4.1.4)</code> | JWK セット URL |
| <code>[jwk](https://tools.ietf.org/html/rfc7516#section-4.1.5)</code> | JSON Web キー |
| <code>[kid](https://tools.ietf.org/html/rfc7516#section-4.1.6)</code> | キー ID |
| <code>[x5u](https://tools.ietf.org/html/rfc7516#section-4.1.7)</code> | X.509 URL |
| <code>[x5c](https://tools.ietf.org/html/rfc7516#section-4.1.8)</code> | X.509 証明書チェーン |
| <code>[x5t](https://tools.ietf.org/html/rfc7516#section-4.1.9)</code> | X.509 証明書 SHA-1 Thumbprint |
| <code>[x5t#S256](https://tools.ietf.org/html/rfc7516#section-4.1.10)</code> | X.509 証明書 SHA-256 Thumbprint |
| <code>[typ](https://tools.ietf.org/html/rfc7516#section-4.1.11)</code> | JWE 自身のメディアタイプ |
| <code>[cty](https://tools.ietf.org/html/rfc7516#section-4.1.12)</code> | ペイロードのメディアタイプ |
| <code>[crit](https://tools.ietf.org/html/rfc7516#section-4.1.13)</code> | 必須パラメーター群指定 |


### **4.6. その他の JWE フィールド**

説明は割愛します。詳細は [RFC 7516](https://tools.ietf.org/html/rfc7516) を参照してください。


# **5. JSON Web Key (JWK)**

JWS の署名や JWE の暗号に非対称鍵系アルゴリズムが使われている場合、そのような JWS や JWE を受け取った側は、署名を検証したり暗号文を復号化するために、署名・暗号で使用された鍵とペアとなる鍵が必要となります。これは、何らかの形で鍵に関する情報を表現し、JWS や JWE を受け取った側に渡す必要があるということです。

そこで登場するのが、**[RFC 7517](https://tools.ietf.org/html/rfc7517)** (**JSON Web Key** (**JWK**)) です。この仕様により、暗号鍵の情報を JSON 形式で表現することができるようになりました。


### **5.?. TODO**

<strike>後日追記します。</strike> 動画『[OAuth & OIDC 入門編](https://www.youtube.com/watch?v=PKPj_MmLq5E)』の [1:06:26](https://youtu.be/PKPj_MmLq5E?t=3986) 〜 をご覧ください。


# **6. JSON Web Token (JWT)**

JWS と JWE の説明が済んでいるので、**JWT** の説明をすることができます。JWT はジョットと読みます。この読み方は、[RFC 7519](https://tools.ietf.org/html/rfc7519) の [Introduction](https://tools.ietf.org/html/rfc7519#section-1) に書かれています。

> The suggested pronunciation of JWT is the same as the English word **"jot"**.

JWT の仕様は **[RFC 7519](https://tools.ietf.org/html/rfc7519)** (**JSON Web Token** (**JWT**)) で定められています。簡単に言うと、**「JWT とは、JSON 形式で表現されたクレーム (claim) の集合を、JWS もしくは JWE に埋め込んだもの」**です。

「JSON 形式で表現されたクレームの集合」がどのように JWS や JWE に埋め込まれるのかを先に説明し、その後、クレーム集合の部分を説明します。


### **6.1. JWS 形式の JWT**

JWS 形式の JWT の場合、JSON 形式で表現されたクレームの集合は、BASE64URL エンコード後、JWS の二番目のフィールドに埋め込まれます。

![jws-jwt.png](https://qiita-image-store.s3.amazonaws.com/0/106044/90498c26-02de-459c-5efe-5cab6bb543a4.png)


### **6.2. JWE 形式の JWT**

JWE 形式の JWT の場合は、クレームの集合は平文として用いられ、暗号化と BASE64URL エンコードを経て、JWE の四番目のフィールドに埋め込まれます。

![jwe-jwt.png](https://qiita-image-store.s3.amazonaws.com/0/106044/d6aab71a-e736-0f6a-4e0d-0acb537f239f.png)


### **6.3. Nested JWT**

署名もしたいし暗号化もしたい、という場合、JWS を JWE でくるむか、もしくはその逆で、JWE を JWS でくるむか、のどちらかをおこなえば実現できます。このように、JWE/JWS の中に JWS/JWE がネストしている形式の JWT は、**Nested JWT** と呼ばれます。次の図は、JWS が JWE に含まれているパターンの Nested JWT を示しています。

![nested-jwt.png](https://qiita-image-store.s3.amazonaws.com/0/106044/479f3b7e-aa12-7878-393a-80f2871bd893.png)

なお、ID トークンの文脈では、署名は必須で、暗号化をする場合は「signed then encrypted」(署名後に暗号化) という順番が MUST とされています。

> ([OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html), [2. ID Token](http://openid.net/specs/openid-connect-core-1_0.html#IDToken) より抜粋)
>
> ID Tokens **MUST be signed** using [JWS](https://tools.ietf.org/html/rfc7515) and optionally both signed and then encrypted using [JWS](https://tools.ietf.org/html/rfc7515) and [JWE](https://tools.ietf.org/html/rfc7516) respectively, thereby providing authentication, integrity, non-repudiation, and optionally, confidentiality, per Section 16.14. If the ID Token is encrypted, it **MUST be signed then encrypted**, with the result being a **Nested JWT**, as defined in [JWT](https://tools.ietf.org/html/rfc7519).

そのため、暗号化された ID トークンは、ちょうど上記の図と同じ「JWS が JWE に含まれている形の Nested JWT」になります。

説明が前後してしまいましたが、**ID トークンは JWT の一種です**。


### **6.4. JWT クレーム**

JWT はクレームの集合なわけですが、形式的には、クレームは JSON オブジェクト内のキー・バリューのペアとして表現されています。つまり、クレーム集合の部分は次のような形式になっています。

```json
{
    "クレーム名": クレーム値,
    "クレーム名": クレーム値,
    ......
}
```

次に挙げる JSON は、[RFC 7519](https://tools.ietf.org/html/rfc7519) の「[3.1. Example JWT](https://tools.ietf.org/html/rfc7519#section-3.1)」から抜粋したクレーム集合部分の例です。

```json
{"iss":"joe",
 "exp":1300819380,
 "http://example.com/is_root":true}
```

[RFC 7519](https://tools.ietf.org/html/rfc7519) では、「[4.1. Registered Claim Names](https://tools.ietf.org/html/rfc7519#section-4.1)」において幾つかクレーム名を定義しています。


| クレーム名 | 説明 |
|:----------|:----|
| <code>[iss](https://tools.ietf.org/html/rfc7519#section-4.1.1)</code> | Issuer クレーム |
| <code>[sub](https://tools.ietf.org/html/rfc7519#section-4.1.2)</code> | Subject クレーム |
| <code>[aud](https://tools.ietf.org/html/rfc7519#section-4.1.3)</code> | Audience クレーム |
| <code>[exp](https://tools.ietf.org/html/rfc7519#section-4.1.4)</code> | Expiration Time クレーム |
| <code>[nbf](https://tools.ietf.org/html/rfc7519#section-4.1.5)</code> | Not Before クレーム |
| <code>[iat](https://tools.ietf.org/html/rfc7519#section-4.1.6)</code> | Issued At クレーム |
| <code>[jti](https://tools.ietf.org/html/rfc7519#section-4.1.7)</code> | JWT ID クレーム |

「[3.1. Example JWT](https://tools.ietf.org/html/rfc7519#section-3.1)」から抜粋した例にもあるように、クレーム名にはこれら以外のものを用いても構いませんが、名前衝突を避けるなどの配慮が必要です。

JWT に含めるべきクレームとして必須のものは、実はありません。「[4. JWT Claims](https://tools.ietf.org/html/rfc7519#section-4)」の第二段落には次のように書かれており、JWT がどのようなクレーム群を含むべきかは、JWT を利用する個々のアプリケーションの定める範疇としています。

> **The set of claims that a JWT must contain to be considered valid is context dependent and is outside the scope of this specification.** Specific applications of JWTs will require implementations to understand and process some claims in particular ways.  However, in the absence of such requirements, all claims that are not understood by implementations MUST be ignored.

[RFC 7519](https://tools.ietf.org/html/rfc7519) の立場から見ると、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) が定める ID トークンは、JWT 応用例の一つとなります。勘の良い方はすぐに予想されたかもしれませんが、ID トークンの仕様では、[RFC 7519](https://tools.ietf.org/html/rfc7519) で定義されているクレームの幾つかが必須のクレームとされています。具体的には、`iss`, `sub`, `aud`, `exp`, `iat` は必須とされています。


# **7. ID トークン**

JWT の説明が済んだので、いよいよ **ID トークン**の説明に入ります。

既に述べてはいますが、改めまして、**ID トークンは JWT の一種です**。ここで、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の「[2. ID Token](http://openid.net/specs/openid-connect-core-1_0.html#IDToken)」の第一段落を見てみましょう。

> **The primary extension that OpenID Connect makes to OAuth 2.0** to enable End-Users to be Authenticated **is the ID Token data structure**. The ID Token is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when using a Client, and potentially other requested Claims. **The ID Token is represented as a JSON Web Token (JWT)**.

これによれば、OpenID Connect が OAuth 2.0 に対しておこなった主要な拡張が、まさに ID トークンというデータ構造だということが分かります。ID トークンが JWT として表現されることも、この段落の末尾に明記されています。

ID トークンには、エンドユーザー認証に関するクレーム群 (Claims about the Authentication) とその他のクレーム群が含まれます。ID トークンで利用するクレーム群のうち、主要なものは [OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の「[2. ID Token](http://openid.net/specs/openid-connect-core-1_0.html#IDToken)」と「[5.1. Standard Claims](http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)」で説明されています。また、細かい話ですが、「[3.3.2.11. ID Token](http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken)」では、`at_hash`, `c_hash` というクレームも定義されています。

それでは、ID トークンのクレームを一つ一つ見ていくことにします。

### **7.1. iss クレーム**

| 仕様 | 説明  |
|:--|:--|
| [RFC 7519](https://tools.ietf.org/html/rfc7519) | The "iss" (issuer) claim identifies the principal that issued the JWT. The processing of this claim is generally application specific. The "iss" value is a case-sensitive string containing a StringOrURI value. Use of this claim is OPTIONAL. |
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | REQUIRED. Issuer Identifier for the Issuer of the response. The `iss` value is a case sensitive URL using the `https` scheme that contains scheme, host, and optionally, port number and path components and no query or fragment components. |

`iss` クレームは、JWT の発行者 (issuer) を識別するための識別子です。`iss` クレームの値は、[RFC 7519](https://tools.ietf.org/html/rfc7519) では文字列か URI (StringOrURI) とされていますが、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) のほうの定義では、より条件が多くなっており、「`https://` で始まる URL (ただしクエリー部とフラグメント部は含まない)」とされています。

次に挙げる例は、`iss` クレームの値として有効な URL です。

```
https://example.com
```

ID トークン発行サーバーは、他者の識別子との衝突を避けるため、`iss` クレームの値を自分の管理下にあるドメイン名の URL とすべきです。これに加えて、もしも、**[OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html)** という仕様をサポートするのであれば、「`{issクレームの値}/.well-known/openid-configuration`」という URL でリクエストを受け付ける必要があることを念頭に置いて `iss` クレームの値を決める必要があります。

例えば、もし上記の例のように `iss` クレームの値を `https://example.com` とし、かつ、[OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) をサポートするのであれば、次の URL で HTTP GET リクエストを受け付けて適切な JSON データを返せなければなりません。

```
https://example.com/.well-known/openid-configuration
```

参考までに、Google 社による実装はこちらになります。
&nbsp; &nbsp; &nbsp; &nbsp; <code>https://accounts.google.com/.well-known/openid-configuration</code>


### **7.2. sub クレーム**

| 仕様 | 説明  |
|:--|:--|
| [RFC 7519](https://tools.ietf.org/html/rfc7519) | The "sub" (subject) claim identifies the principal that is the subject of the JWT.  The claims in a JWT are normally statements about the subject.  The subject value MUST either be scoped to be locally unique in the context of the issuer or be globally unique. The processing of this claim is generally application specific.  The "sub" value is a case-sensitive string containing a StringOrURI value.  Use of this claim is OPTIONAL. |
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | REQUIRED. Subject Identifier. A locally unique and never reassigned identifier within the Issuer for the End-User, which is intended to be consumed by the Client, e.g., `24400320` or `AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4`. It MUST NOT exceed 255 ASCII characters in length. The `sub` value is a case sensitive string. |

`sub` クレームは、ユーザーの一意識別子を表します。値の形式は、[RFC 7519](https://tools.ietf.org/html/rfc7519) では文字列か URI (StringOrURI) とされており、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) では 255 文字以内の ASCII 文字列とされています。

突然、「ユーザーの一意識別子」というものがでてきました。これまで説明はしていませんでしたが、ID トークンはユーザーを認証した結果発行されるものなので、どのユーザーが認証されたのかの情報が含まれることになります。その「どのユーザーが認証されたのか」という情報にあたる部分が、`sub` クレームです。`sub` クレームの値は、ID トークン発行者のシステム内において、ユーザーを一意に特定することが可能な識別子です。

ユーザーの一意識別子は、一般的には、データベース内のユーザーテーブルのプライマリーキーやそれに準ずるものです。特に気にしないのであれば、プライマリーキーの値をそのまま `sub` の値として用いてもかまいません。気にするのであれば、何らかのロジックを用いて元々の値を変換してから `sub` クレームの値として用いることになります。場合によっては、ID トークンの発行を依頼したプログラムの違いによって、同じプライマリーキーから異なる `sub` クレーム値を生成してもかまいません。これについては、[OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の「[8. Subject Identifier Types](http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes)」に言及があります。


### **7.3. aud クレーム**

| 仕様 | 説明  |
|:--|:--|
| [RFC 7519](https://tools.ietf.org/html/rfc7519) | The "aud" (audience) claim identifies the recipients that the JWT is intended for.  Each principal intended to process the JWT MUST identify itself with a value in the audience claim.  If the principal processing the claim does not identify itself with a value in the "aud" claim when this claim is present, then the JWT MUST be rejected.  In the general case, the "aud" value is an array of case-sensitive strings, each containing a StringOrURI value.  In the special case when the JWT has one audience, the "aud" value MAY be a single case-sensitive string containing a StringOrURI value.  The interpretation of audience values is generally application specific. Use of this claim is OPTIONAL. |
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | REQUIRED. Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 `client_id` of the Relying Party as an audience value. It MAY also contain identifiers for other audiences. In the general case, the `aud` value is an array of case sensitive strings. In the common special case when there is one audience, the `aud` value MAY be a single case sensitive string. |

`aud` クレームは、当該 JWT が、誰を対象として発行されたのかを示すものです。別の言い方をすると、JWT の受け取り手が誰であるべきかを示しています。ID トークンの場合、この `aud` クレームの値は、ID トークンの発行を依頼したクライアントアプリケーションのクライアント ID となります。


### **7.4. exp クレーム**

| 仕様 | 説明  |
|:--|:--|
| [RFC 7519](https://tools.ietf.org/html/rfc7519) | The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing.  The processing of the "exp" claim requires that the current date/time MUST be before the expiration date/time listed in the "exp" claim. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew.  Its value MUST be a number containing a NumericDate value.  Use of this claim is OPTIONAL. |
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | REQUIRED. Expiration time on or after which the ID Token MUST NOT be accepted for processing. The processing of this parameter requires that the current date/time MUST be before the expiration date/time listed in the value. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. See [RFC 3339](https://tools.ietf.org/html/rfc3339) for details regarding date/times in general and UTC in particular. |

`exp` クレームは JWT の有効期限を示しています。ID トークンでは、Unix エポック (1970 年 1 月 1 日 (世界標準時)) からの経過秒数となっています。単位はミリ秒ではなく秒なので、ID トークンを生成もしくはパースするプログラムを書く際には注意が必要です。


### **7.5. iat クレーム**

| 仕様 | 説明  |
|:--|:--|
| [RFC 7519](https://tools.ietf.org/html/rfc7519) | The "iat" (issued at) claim identifies the time at which the JWT was issued.  This claim can be used to determine the age of the JWT.  Its value MUST be a number containing a NumericDate value.  Use of this claim is OPTIONAL. |
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | REQUIRED. Time at which the JWT was issued. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. |

`iat` クレームは JWT が発行された日時を示しています。`exp` クレームと同様、Unix エポックからの経過秒数で表現されています。


### **7.6. auth_time クレーム**

| 仕様 | 説明  |
|:--|:--|
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | Time when the End-User authentication occurred. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. When a `max_age` request is made or when `auth_time` is requested as an Essential Claim, then this Claim is REQUIRED; otherwise, its inclusion is OPTIONAL. (The `auth_time` Claim semantically corresponds to the OpenID 2.0 [PAPE](http://openid.net/specs/openid-provider-authentication-policy-extension-1_0.html) `auth_time` response parameter.) |

`auth_time` クレームは、ユーザーが認証された時刻を Unix エポックからの経過秒数で表現しています。このクレームは [RFC 7519](https://tools.ietf.org/html/rfc7519) では定義されていません。

ユーザー認証は、ID トークンの発行と同じタイミングで実行されるとは限りません。認証後しばらくたってから ID トークン発行依頼が届いたものの、「既にログイン状態だから認証が終わっているものとみなす」ということで、認証処理をスキップして ID トークンが発行されることがあります。このようなケースの場合、ユーザーが認証された時刻 (`auth_time`) と ID トークンが発行された時刻 (`iat`) には、差がでてきます。

`auth_time` クレームを ID トークンに含めるかどうかは、基本的には任意です。しかし、ID トークン発行依頼が「認証後許容経過時間」を指定する `max_age` リクエストパラメーターを伴っていたり (「[OAuth & OpenID Connect 関連仕様まとめ](http://qiita.com/TakahikoKawasaki/items/185d34814eb9f7ac7ef3)」の「[17. 認証後許容経過時間](http://qiita.com/TakahikoKawasaki/items/185d34814eb9f7ac7ef3#17-%E8%AA%8D%E8%A8%BC%E5%BE%8C%E8%A8%B1%E5%AE%B9%E7%B5%8C%E9%81%8E%E6%99%82%E9%96%93)」参照)、ID トークン発行依頼を出したクライアントアプリケーションのメタ情報設定が「ID トークン発行時に `auth_time` クレームを必須とする」となっていたりすると ([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)」の `require_auth_time` 参照)、`auth_time` クレームは必須となります。


### **7.7. nonce クレーム**

| 仕様 | 説明  |
|:--|:--|
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. If present in the ID Token, Clients MUST verify that the `nonce` Claim Value is equal to the value of the `nonce` parameter sent in the Authentication Request. If present in the Authentication Request, Authorization Servers MUST include a `nonce` Claim in the ID Token with the Claim Value being the nonce value sent in the Authentication Request. Authorization Servers SHOULD perform no other processing on `nonce` values used. The `nonce` value is a case sensitive string. |

主に[リプレイアタック](https://ja.wikipedia.org/wiki/%E5%8F%8D%E5%B0%84%E6%94%BB%E6%92%83)を防ぐ目的で、ID トークン発行依頼に `nonce` というリクエストパラメーターが付いてくることがあります。このとき、ID トークン発行側は、受け取った `nonce` の値をそのまま ID トークンに埋め込みます。


### **7.8. acr クレーム**

| 仕様 | 説明  |
|:--|:--|
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | OPTIONAL. Authentication Context Class Reference. String specifying an Authentication Context Class Reference value that identifies the Authentication Context Class that the authentication performed satisfied. The value "0" indicates the End-User authentication did not meet the requirements of [ISO/IEC 29115](http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=45138) level 1. Authentication using a long-lived browser cookie, for instance, is one example where the use of "level 0" is appropriate. Authentications with level 0 SHOULD NOT be used to authorize access to any resource of any monetary value. (This corresponds to the OpenID 2.0 OpenID 2.0 [PAPE](http://openid.net/specs/openid-provider-authentication-policy-extension-1_0.html) `nist_auth_level` 0.) An absolute URI or an [RFC 6711](https://tools.ietf.org/html/rfc6711) registered name SHOULD be used as the `acr` value; registered names MUST NOT be used with a different meaning than that which is registered. Parties using this claim will need to agree upon the meanings of the values used, which may be context-specific. The `acr` value is a case sensitive string. |

`acr` クレームは、ユーザー認証が満たした認証コンテキストのクラスを示しています。例えば、パスワードによる認証という基準を満たしたとか、X.509 での認証という基準を満たした、というような情報です。認証コンテキストに関連する仕様についは、「[OAuth & OpenID Connect 関連仕様まとめ](http://qiita.com/TakahikoKawasaki/items/185d34814eb9f7ac7ef3)」の「[16. 認証コンテキストクラス](http://qiita.com/TakahikoKawasaki/items/185d34814eb9f7ac7ef3#16-%E8%AA%8D%E8%A8%BC%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%AF%E3%83%A9%E3%82%B9)」を参照してください。


### **7.9. amr クレーム**

| 仕様 | 説明  |
|:--|:--|
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | OPTIONAL. Authentication Methods References. JSON array of strings that are identifiers for authentication methods used in the authentication. For instance, values might indicate that both password and OTP authentication methods were used. The definition of particular values to be used in the `amr` Claim is beyond the scope of this specification. Parties using this claim will need to agree upon the meanings of the values used, which may be context-specific. The `amr` value is an array of case sensitive strings. |

`amr` クレームは、認証手法を示しています。その具体的な値については、(少なくとも) [OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) の仕様の範囲外とされており、`amr` クレームの利用者が規則を決めて運用すべきもの、という扱いになっています。


### **7.10. azp クレーム**

| 仕様 | 説明  |
|:--|:--|
| [OIDC Core](http://openid.net/specs/openid-connect-core-1_0.html) | OPTIONAL. Authorized party - the party to which the ID Token was issued. If present, it MUST contain the OAuth 2.0 Client ID of this party. This Claim is only needed when the ID Token has a single audience value and that audience is different than the authorized party. It MAY be included even when the authorized party is the same as the sole audience. The `azp` value is a case sensitive string containing a StringOrURI value. |

`azp` クレームは、認可された対象者を示しています。認可されたクライアントアプリケーションのクライアント ID の値です。このクレームは、ID トークンの発行を依頼したクライアントアプリケーションと認可されたクライアントアプリケーションが異なる場合、必要となります。しかし、発行依頼したクライアントと認可されたクライアントが異なるというのは、あまりきかないユースケースです。


### **7.11. ユーザー属性クレーム群**

ユーザーの属性に関するクレームは、「[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` | Web サイトやブログの URL |
| `email` | メールアドレス |
| `email_verified` | メールアドレスが検証済みか否かの真偽値 |
| `gender` | 性別。`female` と `male` が定義済み。 |
| `birthdate` | 誕生日。`YYYY-MM-DD` という書式。 |
| `zoneinfo` | タイムゾーン。`Europe/Paris` など。 |
| `locale` | ロケール。`en-US` など。 |
| `phone_number` | 電話番号 |
| `phone_number_verified` | 電話番号が検証済みか否かの真偽値 |
| `address` | 住所。書式は「[5.1.1. Address Claim](http://openid.net/specs/openid-connect-core-1_0.html#AddressClaim)」に記載。 |
| `updated_at` | 情報最終更新日。Unix エポックからの経過秒数。 |

これらのクレーム群を ID トークンに含める際、クレームによっては多言語化可能なものがあります。例えば、`family_name` クレームの場合、英語なら「Kawasaki」、日本語なら「川崎」や「カワサキ」というように、値が幾つか考えられます。このような多言語化への対応のため、クレーム名の後ろに「<code>#<i>言語タグ</i></code>」をつけるという仕組みがあり、「[5.2. Claims Languages and Scripts](http://openid.net/specs/openid-connect-core-1_0.html#ClaimsLanguagesAndScripts)」で詳細に説明されています。

次の JSON の断片は、言語タグ付きの `family_name` クレームの例です。

```json
{
    "family_name": "Kawasaki",
    "family_name#ja-Hani-JP": "川崎",
    "family_name#ja-Kana-JP": "カワサキ",
```

言語タグそのものの詳細については [RFC 5646](https://tools.ietf.org/html/rfc5646) (Tags for Identifying Languages) を参照してください。


### **7.12. ハイブリッドフロー関連のクレーム群**

詳細は後編で説明する予定ですが、ID トークンと同時に、アクセストークンや認可コードというものが一緒に発行される場合があります。もしこれらが同時に発行される場合、ID トークンに幾つかクレームが追加されます。「[3.3.2.11. ID Token](http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken)」に詳細説明があります。

| クレーム名 | 説明 |
|:--|:--|
| `at_hash` | Access Token hash value. Its value is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the `access_token` value, where the hash algorithm used is the hash algorithm used in the `alg` Header Parameter of the ID Token's JOSE Header. For instance, if the `alg` is `RS256`, hash the `access_token` value with SHA-256, then take the left-most 128 bits and base64url encode them. The `at_hash` value is a case sensitive string. If the ID Token is issued from the Authorization Endpoint with an `access_token` value, which is the case for the `response_type` value `code id_token token`, this is REQUIRED; otherwise, its inclusion is OPTIONAL. |
| `c_hash` | Code hash value. Its value is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the `code` value, where the hash algorithm used is the hash algorithm used in the `alg` Header Parameter of the ID Token's JOSE Header. For instance, if the `alg` is `HS512`, hash the `code` value with SHA-512, then take the left-most 256 bits and base64url encode them. The `c_hash` value is a case sensitive string. If the ID Token is issued from the Authorization Endpoint with a `code`, which is the case for the `response_type` values `code id_token` and `code id_token token`, this is REQUIRED; otherwise, its inclusion is OPTIONAL. |

ID トークンと同時にアクセストークンも発行される場合、`at_hash` というクレームが追加されます。`at_hash` の値は、アクセストークンのハッシュをとり、結果として得られたハッシュ値の左半分のビット群を base64url でエンコードしたものです。同様に、認可コードが同時に発行される場合は、`c_hash` というクレームが追加されます。

加えて、`nonce` クレームが必須となります。


# **まとめ**

**「OpenID Connect は『ID トークン』を発行するための仕様である」**という割り切り方のもと、**ID トークン**とは具体的にどんなものであるかを理解することに努めました。

ID トークンは、形式は **JWT** ([RFC 7519](https://tools.ietf.org/html/rfc7519))、意味内容はクレームの集合、ということが分かりました。JWT という形式なので、署名や暗号化が可能であり、認証の事実やユーザー属性情報のやりとりが、より安全に行えるようになっています。

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

* [OAuth & OpenID Connect 関連仕様まとめ](http://qiita.com/TakahikoKawasaki/items/185d34814eb9f7ac7ef3)
* [OAuth & OpenID Connect の不適切実装まとめ](http://qiita.com/TakahikoKawasaki/items/efbbd2c5875577c911a3)
* [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)
* [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)

<hr/>

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