【Auth0】テナント毎のJSON Web Key Setの場所

# はじめに
Auth0が発行するIDトークンやJWTなアクセストークン（RS256での署名付与）についている署名を検証するための公開鍵を表しているJSON Web Key Setの配置場所をご紹介します。

# JSON Web Key Set エンドポイント

JSON Web Key Setはテナント単位に保持されていて、テナント内の登録アプリケーション全てで共通的に使用します。
以下ような形式のURLにアクセスすると`jwks.json`というjsonファイルの形式でJSON Web Key Setが配置されています。

```
https://{Auth0テナントのドメイン}/.well-known/jwks.json
```

アクセスすると改行やインデントが入っていないjsonファイルが取得できます。

```json:jwks.json
{"keys":[{"alg":"RS256","kty":"RSA","use":"sig","n":"7wNmdmdOONj9227brmWrUlVVaEIHGpm_rykW7Llbm6HHZCa4emqRhyLqUyy5ywZD_r2LwZ8waKVpliQ7msusKqDD84PxnKyXi_IiVGBne3yB84NAZE187WwUnBr-5RM0uBW05XJnQc_pcr9FagJbSFxsW0DAQb2Eo9HLfW970oRfi3EanOpkwaR4mQJ6BMIzgQX7Cro6qv6yoTr8Q2L10oykP-dBdz2zQKZ6hsYoLIdBQ2Ot0kYeUZplHdsRN_PMxg_1KN8gyET1OMdilHo4mzhU28GxgqNLS6UEsuTNqpapIZd_y_1cNZBTRNBAo9AL2WJSYIWVTHVJGFJ0qy1tRw","e":"AQAB","kid":"NjJDNEMzQUExQTQwREE0NUYxNTdFMUZFOEZBQkNGQzJDRkQzOEFGNQ","x5t":"NjJDNEMzQUExQTQwREE0NUYxNTdFMUZFOEZBQkNGQzJDRkQzOEFGNQ","x5c":["MIIDATCCAemgAwIBAgIJbKQsnfJ32C8PMA0GCSqGSIb3DQEBCwUAMB4xHDAaBgNVBAMTE2NodWRlbi1pZC5hdXRoMC5jb20wHhcNMTkxMTA3MDE1MzU3WhcNMzMwNzE2MDE1MzU3WjAeMRwwGgYDVQQDExNjaHVkZW4taWQuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7wNmdmdOONj9227brmWrUlVVaEIHGpm/rykW7Llbm6HHZCa4emqRhyLqUyy5ywZD/r2LwZ8waKVpliQ7msusKqDD84PxnKyXi/IiVGBne3yB84NAZE187WwUnBr+5RM0uBW05XJnQc/pcr9FagJbSFxsW0DAQb2Eo9HLfW970oRfi3EanOpkwaR4mQJ6BMIzgQX7Cro6qv6yoTr8Q2L10oykP+dBdz2zQKZ6hsYoLIdBQ2Ot0kYeUZplHdsRN/PMxg/1KN8gyET1OMdilHo4mzhU28GxgqNLS6UEsuTNqpapIZd/y/1cNZBTRNBAo9AL2WJSYIWVTHVJGFJ0qy1tRwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2BgDESdQwf5ZKp+/X7dHTw6w3tDAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBACmEqsvGjwW3MyHMJi0JviPWWYt7gh8tLRld/C+o11FnyfKuLRTH2JbUtF79p8q3kr5Cmp5xKwyR6zXO3PiGWpdwWm08wneMnlUPULgsGXkrkt62xfj2OW+y3atpQh1EGs+KmYgicryoprzqHBgKThbGohJWlKr0n2t8I/g2FfNSDwlpA/ehyzt2wrtRC8UBdqg/HejK73lgwX/zsfGWF/WaDBgUkUGlS/Oa+pdoWuibOAORk4F1OXnif4tc7l8X0UG/pjmE+1B3EwmISFFxXPdhHglzmlrmbSDZpCleDgrXNLAH9SAkt12ychdGFq8i2B5pBnkVRBa0/PYAHSnbGZ8="]},{"alg":"RS256","kty":"RSA","use":"sig","n":"2YlIJ1WnOOAXQuZIlOQPJpmOvxu8aZmToxdBG1Sipdq-oGTeRE-NOku1V5cD1-Zo4PVEOWa1no6EHlgC-w2NPaPJBNcRSEKpWM0ZeCKNHuHby9CYaiYPqfdc4UzJiI9d-C_LKNdV6xfZJE2U7CcfgO_4lON4nxbVmUlueJ69NDkUdphke4-nmgZpMTl8sJqTrSSVlZxHoc7JdDRUsO59PLWtMQVbQX_ajhMre4yJsHIWwh7gboMpZh_7RWfN_MuEzjOeV9pT0siRHRhUZ7fAvQcqEUtGZ_o7iBYp8m05QKQ10qgHUG6EleLTmUDtAof8yWHd8KhdpmO_mHlR-RNE1w","e":"AQAB","kid":"yx33mK8zO4dPDVMporJTP","x5t":"hywOlmGteDckgGt1uktbzz_ca0E","x5c":["MIIDATCCAemgAwIBAgIJIkavwfTsaRrtMA0GCSqGSIb3DQEBCwUAMB4xHDAaBgNVBAMTE2NodWRlbi1pZC5hdXRoMC5jb20wHhcNMjAwMzE3MjExMDEzWhcNMzMxMTI0MjExMDEzWjAeMRwwGgYDVQQDExNjaHVkZW4taWQuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2YlIJ1WnOOAXQuZIlOQPJpmOvxu8aZmToxdBG1Sipdq+oGTeRE+NOku1V5cD1+Zo4PVEOWa1no6EHlgC+w2NPaPJBNcRSEKpWM0ZeCKNHuHby9CYaiYPqfdc4UzJiI9d+C/LKNdV6xfZJE2U7CcfgO/4lON4nxbVmUlueJ69NDkUdphke4+nmgZpMTl8sJqTrSSVlZxHoc7JdDRUsO59PLWtMQVbQX/ajhMre4yJsHIWwh7gboMpZh/7RWfN/MuEzjOeV9pT0siRHRhUZ7fAvQcqEUtGZ/o7iBYp8m05QKQ10qgHUG6EleLTmUDtAof8yWHd8KhdpmO/mHlR+RNE1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgNCQtESyPVmxdSUklPZseW1Bp0TAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBALjS48q3p17EYHZLDxgwbw0UT3UzOkruFC56ETPU92mLZN8Za28FcRs+pFyu6epQJUHJcwsSALbv/xqg91z++o0Fxoghe2v3hXfuk7fAP63Hh3b/jrbeM3uDElAkOo2QddzLF/ddyAL1rPJV6s719+enGYa/8NedLVowO0xPxCwXiwUNhvS2yiQW9bTz07W/jXmNPEG/CC94L+u/NbsxiAivTh+/bahFeklQmMmyouHoh5eqdj80KAeSP/r6unfX0tb+M5PdG5qJZtm17UgbFtdqw22pzEaYbVRL+r8M8SOsh9JrZPp8VeKt6HAh9qUQj4yfOmcCReCXIuBqne1uqt8="]}]}
```

これを見やすくするために改行とインデントをいれると、こうなります。

```json:jwks.json
{
  "keys": [
    {
      "alg": "RS256",
      "kty": "RSA",
      "use": "sig",
      "n": "vFW7DrS4pKe0eXRU74GfTvc7MC7VVa0Qkf6llmGWHJR3QUNH6pI9d5V9pXj0MQbrk3AJy3rQ9KbrQoDbdLLqlfG8orAKCUiYsEyumzs916_f16xI7hM-xl0ktdS_aSazblXjrQJeA875zg-YTBMT2rZLAZ4V3OgXd_gp4t7vmvk4b_5akHJkjh2mL6Cea-ilLwWr6N2haqrlk1c-8c56PUaQ67RlRk8yrESAC0RjMsewGe_QNqIlzefuqJlb1wCddalCa9zVuubSNbWs2IMopaavluzUss3T0D3bbRu2tlSxlqzoIDfWqfDZrQ_mMS5mKUh9ljdfIWIMY7B2VE1UIw",
      "e": "AQAB",
      "kid": "huABlEJfZ6Mb3MC_WYKip",
      "x5t": "jsGgQ39zYpz7lqIwHi8-3-VxSWk",
      "x5c": [
        "MIIDBTCCAe2gAwIBAgIJe1swZUvSillLMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFW1vcmlrYXdhLnVzLmF1dGgwLmNvbTAeFw0yMDA3MjAwMTEyMThaFw0zNDAzMjkwMTEyMThaMCAxHjAcBgNVBAMTFW1vcmlrYXdhLnVzLmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxVuw60uKSntHl0VO+Bn073OzAu1VWtEJH+pZZhlhyUd0FDR+qSPXeVfaV49DEG65NwCct60PSm60KA23Sy6pXxvKKwCglImLBMrps7Pdev39esSO4TPsZdJLXUv2kms25V460CXgPO+c4PmEwTE9q2SwGeFdzoF3f4KeLe75r5OG/+WpByZI4dpi+gnmvopS8Fq+jdoWqq5ZNXPvHOej1GkOu0ZUZPMqxEgAtEYzLHsBnv0DaiJc3n7qiZW9cAnXWpQmvc1brm0jW1rNiDKKWmr5bs1LLN09A9220btrZUsZas6CA31qnw2a0P5jEuZilIfZY3XyFiDGOwdlRNVCMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSUbprxc86MSO3+D7v3WnNtnKMjMwDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQCoL3YaMdP6hVqOnK8xif3sHWcbed2zS2YwQSjl8dWJXzvg9vDh/SfY07851+vk6ek2Te2evIiaw4grSJpeb7D5ZJh1YEIMkfkciOcYCTeTZ2VsoQ4MNmS+9+lwhlXLedoY3DFdvrY84bf4w0KHdknjVT98PTvhsS55DBeIhjSpzXEBi3b2nrrti69rwQd/1WuwVEtX+chXvIOI3lw/of0oGUpggAbTMJKPjdfPtDz+sYOiCoK5wn2g2uo09ppqJqGg/H79zR3MGT8yIW5WWnEcRGZmBTjmxRoS5YhqIMlfQB8eH4hXUTJyqBJAap3mWoHmNdq83gY1YwSoavVWXS7f"
      ]
    },
    {
      "alg": "RS256",
      "kty": "RSA",
      "use": "sig",
      "n": "xxQn7Ry1fG0Q6p2_ExbWRyyg7qydjGGwtqfnKlzd55r1GZsRlmwKOTdxndjVdwWyaC1rBNNxgjEsYeSiATdiAOAMlVflFJXflYWstkAnUSVZM9htPmodMF07kytHYal4yXq_lVP026Om0wYva5ld_0UvrGqpICs72T229uFokDtxPhsGOnYwJN5C9jle0N-yWhTmb2YsYRPD2qJl1YmMi1iikkyVT38wic5FUyL6J9NtGw85rFoccDnv9_SqODWo2OplHUhXmLhgpPQDv19fKf6j36X5_-JfbSPK_KkP4iyp8HRvrVo62QqYXzAIgPGoTysN94cdJdz1D7IfOtRchw",
      "e": "AQAB",
      "kid": "9UaIbpxKvvq9vr9gKL8SV",
      "x5t": "ToJiD69L-3SA34ZPnTvYBNIGPLA",
      "x5c": [
        "MIIDBTCCAe2gAwIBAgIJIL0OhFiVxDpdMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMTFW1vcmlrYXdhLnVzLmF1dGgwLmNvbTAeFw0yMDA3MjAwMTEyMTlaFw0zNDAzMjkwMTEyMTlaMCAxHjAcBgNVBAMTFW1vcmlrYXdhLnVzLmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcUJ+0ctXxtEOqdvxMW1kcsoO6snYxhsLan5ypc3eea9RmbEZZsCjk3cZ3Y1XcFsmgtawTTcYIxLGHkogE3YgDgDJVX5RSV35WFrLZAJ1ElWTPYbT5qHTBdO5MrR2GpeMl6v5VT9NujptMGL2uZXf9FL6xqqSArO9k9tvbhaJA7cT4bBjp2MCTeQvY5XtDfsloU5m9mLGETw9qiZdWJjItYopJMlU9/MInORVMi+ifTbRsPOaxaHHA57/f0qjg1qNjqZR1IV5i4YKT0A79fXyn+o9+l+f/iX20jyvypD+IsqfB0b61aOtkKmF8wCIDxqE8rDfeHHSXc9Q+yHzrUXIcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEbVrcAu3eAIjjFGMrKV6vEa9ikwDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQBX6p/vdgqPW20we1cu9RnAMf5/sqSOi8sEMuOmIzPk6ZDY8CuV3N+OYb77axK4raRcjlmc+JCPOG+11l0EfcVhyKdX2Z71LOuT8QnmAshO2qQ34vHNXPfb5QBt8YPumjfi65c9S0jZ7mWs65SivSxTD0mSfM/fMX11Oc6vwCs3x4ej0zVtzYBIwVpSiMwrs2+O04A0//gj6lEWIUUg0vBQfErGzsc52zrkDIJuBkOrV9ST2mH99q10xzGfPW4CNCsYI6RtqkSIAerSchA23UTkRluSU2shdkNWWTgpTkhMIdOBEswAqlAlJV3WgWnRV92EgNCFBkUbkE4DVfEBFMGB"
      ]
    }
  ]
}
```

この例だと`jwks.json`の中には2つの公開鍵（JSON Web Key）が含まれています。
この中から実際に署名付与に使用された秘密鍵に対応する公開鍵を特定するにはJWTのヘッダー内の`kid`プロパティを使用します。
`jwks.json`の中の各公開鍵（JSON Web Key）にも`kid`プロパティが存在するので、`kid`が一致する公開鍵で署名検証ができます。

例えば、IDトークンのヘッダーが以下の場合は上記`jwks.json`の`keys`配列の一番最初の要素が対応する公開鍵になります。

```json
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "huABlEJfZ6Mb3MC_WYKip"
}
```

# おわりに

普段ライブラリを使って署名検証をしているとJSON Web Key Setを意識することは無いかもしれませんが
知識として知っておいた方がいいと思います。