さっしーブログ

埼玉県在住のシステムエンジニアです。基本的には技術的な内容を中心に発信していきます。

【OpenID Connect】公開されているJWKを使用してIDTokenを検証するやり方

目次

 

1. IDTokenを取得する

例えば、googleの場合を例に解説していきます。
 
まずはIDTokenを取得しましょう
 
googleでログインして、
 
 
のエンドポイントへ必要なパラメータを渡してアクセスするとユーザー情報が取得できます。
 
{
  "result": {
  "access_token": "ya29.GltSBB9N9ODliM2OF3RdJhA3b2y9apfY8-u9EFlFbaGcer0M8AhQBZMemMOhOSZYAlnQMJIkahVwfnWy_QjpqTo9p2xV1rKe4naH8Kj2_CeCDqOM0fD1sK0xG3wm",
  "client": "client_sample",
  "email": "sassy@example.co.jp",
  "email_verified": true,
  "family_name": "テスト",
  "given_name": "太郎",
  "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjMwOGYyNDg3NTZiNWY2ZWU0ZGQ0YzVkODBiNTU4NTA5OTdmZmRlN2YifQ.eyJhenAiOiI2Mzc3MDQ1Njk4NTYtczVmaWRoNjMwM2NkNWk4Z2M5OTN1bW10M2pybjE2N2kuYBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2Mzc3MDQ1Njk4NTYtczVmaWRoNjMwM2NkNWk4Z2M5OTN1bW10M2pybjE2N2kuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDc2ODQyMTA4MTk2NDU3OTIyNzUiLCJoZCI6ImduYXZpLmNvLmpwIiwiZW1haWwiOiJzYWlraS15QGduYXZpLmNvLmpwIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF0X2hhc2giOiJmbnBmalV1OXBfZmo5cUJIem9YMkN3IiwiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tIiwiaWF0IjoxNDk1NDUzMzkyLCJleHAiOjE0OTU0NTY5OTIsIm5hbWUiOiLpvYrmnKjoo5XlpKoiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDUuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1mZ3VXbkVyN1VQYy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBcy9GZlIwMjlWN054SS9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoi6KOV5aSqIiwiZmFtaWx5X25hbWUiOiLpvYrmnKgiLCJsb2NhbGUiOiJqYSJ9.4lBc-SD2UsXpicVubvNYiwaaQ6tMWKHROlOhxmYeH6w2ldwNEXdIxXeoiyiSGNv2QrYbrUEYxlueX5EaepBK1-NUCJ0OcJOK-vYBt8X-C8gOrSVV-6vyC8WWrl8l8P0e3DVgRvUSGzYTY0kqbLa2cbkuxYavAjKfPi71XWNjGWU3Rqre3bTaUdIV5EPBCQIgqsH-yZhA6zPkw1jo8a-nRJFySZzbAcREJdxaBDM-GS1jGnX-y2GbZAaADzPpjsLMfxTqUCQvWywEHUyJwg2qivwR8YsFhJoDQX1_1PXtAnlI6rmIB7lbwaSkpz6wF21i0ktFeP2OYlTRXtyw5e_yHg",
  "locale": "ja",
  "name": "テスト太郎",
  "refresh_token": "1/sEBQFEXy2u1aCUf6PF3FXIqMUYkxwTEHFEbqekpf8oM",
  "service": "google",
  "sub": "107684210819645792xxx"
  },
  "status": {
  "code": "200",
  "message": "OK"
  }
}
 

2.IDTokenを解析する

そして、上記赤文字部分のIDTokenを使用して、以下のサイトで解析して見ましょう。
 
 
そうすると右側のDecoded部分に以下のような結果が得られるかと思います。
HEADER:ALGORITHM & TOKEN TYPE
{
  "alg": "RS256",
  "kid": "308f248756b5f6ee4dd4c5d80b55850997ffde7f"
}
 
PAYLOAD:DATA
{
  "azp": "637704569856-s5fidh6303cd5i8gc993ummt3jrn167i.apps.googleusercontent.com",
  "aud": "637704569856-s5fidh6303cd5i8gc993ummt3jrn167i.apps.googleusercontent.com",
  "sub": "107684210819645792275",
  "hd": "gnavi.co.jp",
  "email": "sassy@example.co.jp",
  "email_verified": true,
  "at_hash": "fnpfjUu9p_fj9qBHzoX2Cw",
  "iat": 1495453392,
  "exp": 1495456992,
  "name": "テスト太郎",
  "given_name": "太郎",
  "family_name": "テスト",
  "locale": "ja"
}
 
ここで「alg」と「kid」に着目してみましょう。
 
「alg」はこのIDTokenがどんな暗号化アルゴリズムを使用して暗号化されているかを示しています。
 
また、「kid」は公開鍵エンドポイントにて公開されている複数の鍵のうち、どの公開鍵で検証できるかを示しています。
 
実際に検証する際にはこの「alg」と「kid」を使用します。
 

3.JWKへアクセスして公開鍵情報を取得する

では以下のgoogleが公開しているJWKへアクセス
 
すると以下の公開鍵をjson形式で取得できる。
{
 "keys": [
  {
  "kty": "RSA",
  "alg": "RS256",
  "use": "sig",
  "kid": "308f248756b5f6ee4dd4c5d80b55850997ffde7f",
  "n": "5I-4yApxPzlxsPdO3x5o671FvxjjDUNHQrK88vvLTUcxrPU3sGy13hy4Rca4d-MVcYl_Lo-M2SqKsQVHEIPPE-YFzUUjScM1_XZaOCxapbPBS0iwnF0VhwB1m8DOCJmgmbeWX9KjiFm8nHMmZ5CzRb_ksYk7RgHEXZ-36g9d0bU5pDBxfV2XAVqsL4bBOVhJuh_iw3giceohmIWDEESGNn9zEdxWAAPCFMJEAyrmMIyNVVoGussShp8R0MVwozfK0KyP4sWtcYZqvGSwuBn4gEahTWILnwfclh9YGG2wrjVP7N8BUzlVOIA3CRYx5VEH-x0iN_BDV-wXajowJcq0XQ",
  "e": "AQAB"
  },
  {
  "kty": "RSA",
  "alg": "RS256",
  "use": "sig",
  "kid": "2b2e4d6f1821ad4d76d4553c951b75622acb6539",
  "n": "sS-niSbizdXtky7i34vxeD2eQPxxeWW03dSSJ3EC6aUv_BCc0nqL0gadhCh5i3KQZRYIlfzrbdMnSr9oOJcQkuX6Cxj1hLiEHe9sIdanEb_mQWrIYdI0xITrTVumoRpZeMYC6eXUUAppK0Eskh_O7EAJznrJmiQeFeNtIs7SvPOGWHOlX9GjAUgTgUMfF2GVovX9Jp5UQ-KBJLwmeyT25FxYueCtqOzYvBZ3fKhAXLgzPi7Ae2LfI0plYZ3pCwY_MM2T3G3oOjNyyi3ijEtHhmHMgL_E2ktDa9o_I2fXfHnuxohUWbTixDBh9VZIwmBBPOFezq6S2HvEaMKv-DFsjw",
  "e": "AQAB"
  },
  以下、省略・・・・・
 
その中で「keys」というのがあるのだけど、この「keys」は配列構造になっており、さらにその中の1つ1つが公開鍵である。
さらにその中を確認すると「kid」というのがあり、この「kid」がさきほどのIDTokenを解析した際に取得できた「kid」に紐付いている。
 
ここでどの公開鍵を使用すればよいかがわかるので、「kid」と同階層にある「n」「e」を使用して公開鍵をプログラム内で生成して利用する。
 
つまり、IDTokenを解析した際に取得できた「kid : "308f248756b5f6ee4dd4c5d80b55850997ffde7f"」は、公開鍵エンドポイントで取得したkeys配列の1つ目の「kid : "308f248756b5f6ee4dd4c5d80b55850997ffde7f"」の公開鍵で検証できるよーってことになる。
 

4.実装の流れ

実装の流れとしては、
 
① IDTokenを取得する。
 
② IDTokenをパースする。
 
③ IDTokenから「alg」「kid」を取得する
 
④ 公開エンドポイントへリクエストして公開鍵のjsonを取得する。
 
⑤ ④で取得したjsonの配列をループでまわして、jsonの「kid」と③で取得した「kid」が一致するものを取得する。
 
⑥ 一致した「kid」と同階層にある「n」と「e」も取得する
 
⑦ 「n」と「e」、「alg」を利用して公開鍵を作成する。
 
⑧ ⑦で作成した鍵を使用してIDTokenの検証を行う
 

5.最後に

ちなみに以下にOpenID Connectのライブラリが公開されておりこれを使用して実装した方がかなり楽になります。
ライブラリを使用しないでやるとかなり複雑な実装をしなくてはいけないため、苦労します…笑
 
※Google様なら検証用のライブラリを提供しているので、そちらを使用したほうが良いですが今回は汎用?的なライブラリで実装したので以下を用いております。
 
 
 以上