🐥

KeycloakでのOpenID Connectお勉強メモ #2

26 min read

はじめに

#1 からのつづきです。前回はこのフローを作りました。
今回はこの内容を詳しく見ていきます。

フロー図


Flow_OIDC

参考文献

調べていくにあたり以下の資料を見ながら進めて行きます。

OpenID Connect フローには種類があるということを知る

OpenID Connect Basic Client Implementer's Guide 1.0 日本語訳 - 2. Protocol Elementsに書いてあるように OpenID Connect には以下の種類があります。

  • Authorization Code Flow
  • Implicit Flow
  • Hybrid Flow

ここでは Authorization Code Flow (最も一般的な方法) でやっています。

まずはこれを見ときます。

OpenID Connect Basic Client Implementer's Guide 1.0 日本語訳 - 2.1. Code Flow

Code Flow は以下のステップからなる.

  1. Client は必要なリクエストパラメータを含んだ Authentication Request を構築する.
  2. Client は Authorization Server にリクエストを送信する.
  3. Authorization Server は End-User を認証する.
  4. Authorization Server は End-User の Consent/Authorization を取得する.
  5. Authorization Server は End-User を code とともに Client に戻す.
  6. Client は code を Token Endpoint に送信し, Access Token と ID Token を受け取る.
  7. Client はそれらのトークンを検証し, End-User の Subject Identifier を取得する.

おおざっぱに構成を理解する


-page-1

End-User

ブラウザを操作する人

Relying Party (RP)

OpenID Connect を利用する側

  • Apache + mod-auth-openidc

  • PHP 公式のDockerコンテナを使う

    • apache2が入っている
    • libapache2-mod-auth-openidcも入れます
    • 詳細は Dockerfile 参照
  • libapache2-mod-auth-openidc

    • Apacheのモジュール(アドオンみたいなもの?)でこれを付けるとApacheがOpenID Connectで話せるようになる便利なもの
    • Protected Resource を定義するだけでOPに問い合わせてくれます
    • 今回の場合 /secure 以下のリソースを Protected Resource にしてこのリソースにリクエストがあれば Keycloak に問い合わせするようになります。
  • サイトの構成は以下の通り

    /
    ├── index.html           --- TOP 画面
    ├── loggedout.html       --- ログアウト後の画面
    └── secure (Protedted Resource)
        └── welcome.php      --- ログイン後の画面
    

OpenID Provider (OP)

OpenID Connect を提供する側

  • Keycloak

  • 操作者(End-User)の Account(アカウント) をå保持する

    • Account は UserInfoCredential で構成される
      • UserInfo - 名前とかメールアドレスとか
      • Credential - パスワード
  • RP-Apache(mod-auth-openidc) からリダイレクトされてEnd-userの認証認可を行う

  • RP-Apache(mod-auth-openidc) からのリクエストでEnd-userのUserInfoを提供する

画面フロー

    1. ブラウザから index.html にアクセスしてTOP画面を表示する
    1. Login with Keycloak をクリックすると /secure/welcome.php に遷移する
    1. が、しかし /securemod-auth-openidc が管理する Protected Resource なのである
    1. mod-auth-openidc はすかさず Keycloak にリダイレクトする
    1. Keycloak はログイン画面を表示する
    1. 無事ログインできたら Welcome画面( /secure/welcome.php )を画面に表示する
    1. welcome画面で Logout をクリックするとログアウト処理をして ログアウト完了画面に遷移する
    1. ログアウト完了画面で Goto Top をクリックするとTOP画面に戻る

memo : 今回は 7) 8)の詳細は調査していません、次の記事で...


Screen_Diagram

Keycloakのエンドポイント

フロー図に書いているエンドポイント

Configuration Endpoint

Authorization Endpoint(認可エンドポイント)

Authenticate Endpoint

  • End-Userが提示したCredentialを検証するエンドポイント
  • ここで Credential の検証OKとなるとAuthorization Code(認可コード) を発行して End-User に返す
  • OpenID Connectで明確に定義されたエンドポイントではなく、Authorization Endpointが提供する機能の一部という扱い
  • OpenID Connect Core 1.0 - 3.1.2.3. Authorization Server Authenticates End-User あたりの説明が参考になる
    • ↑に書いてあるとおり End-User の認証方式については規定範疇外 となっていて認証のやり方の細かい方法は書いていないです。このへんが OpenID Connect と FIDO は補完関係 ということなんですね。

Token Endpoint(トークンエンドポイント)

jwks_uri(証明書エンドポイント)

UserInfo Endpoint(ユーザー情報エンドポイント)

フローの詳細

0. Start

ログインを開始するまでのフロー


  • ブラウザ(End-user)が RP の 管理するリソース index.html にアクセスする


-page-2

  • index.html は ログインする前に表示する画面(Protected Resouce ではない)なので、そのまま 200 OK でレスポンスを返す


test-oidc-rp_1.png


1. Login

Keycloakのログイン画面を表示するまでのフロー

  • Login with Keycloak をクリックすると、./secure/welcome.php に遷移(GET)する


-page-2_1

  • リクエストを受けたRPのmod-auth-openidc は 認証が必要なリソースであることを検知する

    memo : 認可が必要なリソースの定義は auth_openidc.conf<Location /secure> でされている

  • mod-auth-openidcはまだアクセストークンを持っていないため、Keycloakからアクセストークンを取得するフローを開始する

    memo : アクセストークンの取得フローが openid-connect であることは auth_openidc.conf で設定されている


  • mod-auth-openidcはまずKeyCloakからOpenID Configuration を取得する

    memo : OpenID Configurationのエンドポイントは auth_openidc.conf で定義されている


-page-3


  • mod-auth-openidc は End-user へレスポンス 302 Found(リダイレクト) を返す

レスポンスは以下の通り

パラメータ 説明 取得元
Location /protocol/openid-connect/auth 認可エンドポイント にリダイレクトすることを指定する OpenID Configurationauthorization_endpoint
response_type code トークン発行手順がcodeであることを示す auth_openidc.confOIDCResponseType
scope openid ID トークンの発行を要求することを示す auth_openidc.confOIDCClientID
client_id test KeyCloakで設定されているクライアント auth_openidc.confOIDCScope
redirect_uri http://test-oidc-rp:8081/secure Keycoakで認証が完了した後にリダイレクトさせてほしい場所。
ここからはKeycloakの制御になって操作を行うがその後にRPに戻ってきてほしいんでここで指定しておく(*1)
auth_openidc.confOIDCRedirectURI

memo : state/nonceもついているけど省略

  • End-user は レスポンスを受け取り、KeyCloak の 認可エンドポイント にすっ飛んで行く


-page-4


  • Keycloak は ログイン画面を返す

    memo : Cookieが大量についてくるけど省略


-page-5


Sign_in_to_Keycloak

2. Get Authorization Code

Username/Passwordを取得してから**Authorization Code(認可コード)**を取得するまでのフロー

memo
操作者がログイン画面でUsername/Passwordを入力して Sign In ボタンをクリックするところから始まります。
ここから先がゴチャゴチャしているんですがフローはノンストップなので操作者にとっては一瞬です。


  • ログイン画面でUsername/Passwordを入力して Sign In すると End-user は KeyCloak の Authenticate Endpoint に POST する

    memo : クエリパラメータでめっちゃ色々ついているけど省略

    • Formデータ

      Form item 説明
      username hoge ユーザー名
      password xxx パスワード


-page-6


  • Keycloak は usernamepassword を検証して認証OKとなれば End-user へレスポンス 302 Found(リダイレクト) を返す

memo : ここに 認可コード が入っている

パラメータ 説明
Location http://test-oidc-rp:8081/secure リダイレクト先
(*1)で指定されたもの
code 050ab57b-64e1-410a-・・・ 認可コード(Authorization Code)
  • End-user は リダイレクトのレスポンスを受けたので、そのままリダイレクト先に飛んでいく


-page-7

3. Get Access Token & ID Token

認可コードを取得してから Access Token(アクセストークン) と ID Token(IDトークン) を取得するまでのフロー


  • mod-auth-openidc は Keycloak の トークンエンドポイント にPOSTする

    • このとき Authorization ヘッダに Basic を設定する

      ヘッダ 説明
      Authorization Basic dGVz... Basic認証であることを示す

      ↑の値なんですが

      Basic dGVzdDozM2I3MzJjNS0wMDZjLTQxNjMtOWM3Yy01NzVhNjBhMmEzNDg=
      

      これは Basic認証であることを意味していて、Basic 以降のBase64をデコードすると

      test:33b732c5-006c-4163-9c7c-575a60a2a348
      

      となっています。

      要はこの値で接続してくるクライアントを認証しています。→9. Client Authentication

      クライアントIDとシークレットは auth_openidc.confOIDCClientID,OIDCClientSecretです。

    • Form

      Form item 説明
      grant_type authorization_code →3.1.3.1. Token Request
      code 050ab57b-64e1-410a-・・・ 先程取得した 認可コード
      redirect_uri http://test-oidc-rp:8081/secure


-page-8


  • Keycloak は Authorizationヘッダの値とか認可コードを検証してOKであればmod-auth-openidcにレスポンス を返す。
    レスポンスはJSON形式で**Access Token(アクセストークン) と ID Token(IDトークン)**が含まれている。

    Key Value 説明
    access_token JWT形式のデータ アクセストークン
    expires_in 60 アクセストークンの有効期限(60秒=1分)
    refresh_expires JWT形式のデータ リフレッシュトークン
    refresh_expires_in 1800 リフレッシュトークンの有効期限(1800秒=30分)
    token_type Bearer トークンタイプ
    id_token JWT形式のデータ IDトークン


-page-9

アクセストークンとは何か

リソースにアクセスするときの許可証。OAuthのそれと同じ。

IDトークンとは何か

ユーザーをちゃんと認証したよ、という証明書みたいなもの。ユーザー名とかの属性も入っている。

詳細は以下のサイトを見たほうがいい


  • 続けざまに KeyCloak の jwks_url(証明書エンドポイント) から証明書をGETする。

    • 証明書 = アクセストークン、IDトークンのJWTの署名を検証するために使う公開鍵

    • ここに入っている公開鍵でJWTを検証することでアクセストークン、IDトークンが改ざんされていないことを確認する

      memo : jwks_url は OpenID Configuration に入っている


    -page-10


  • UserInfo Endpoint(ユーザー情報エンドポイント) からユーザー情報をGETする。

  • ユーザー情報 = UsernameとかEmailとか

    • ユーザー情報エンドポイントにアクセスする際のAuthorizationヘッダはBearerで、先程取得した アクセストークン を指定する

    memo : UserInfo Endpoint は OpenID Configuration に入っている


-page-11


  • ここまででmod-auth-openidc は必要な情報を全て取得したことになる。End-userには一番最初にアクセスを要求されたURLに遷移するリダイレクトのレスポンスを返す。
パラメータ 説明
Location http://test-oidc-rp:8081/secure/welcome.php リダイレクト先


-page-12

4. Resource access

リダイレクト先に遷移する。リクエストを受けた mod-auth-openidc はアクセスを許可しHTMLを返す。

note : mod-auth-openidc は Cookie mod_auth_openidc_session にアクセストークンを紐付けていてアクセストークンの有効性を確認しているようです。mod_auth_openidc_sessionを削除するとKeycloakに問い合わせて再度アクセストークンをもらってきているのでしょう。


-page-13

おつかれさまでした

よくわからないことがまだあるなぁ...

  • ログアウトの動作 (Logout)
  • ログインしたままTOPに戻って再度ログインしたときの動作(Return to top wthile logged in)
  • アクセストークン/IDトークンの有効期限が切れたときの動作

蛇足(データサンプル)

OpenID Configuration

{
  "issuer": "http://test-oidc-keycloak:8080/auth/realms/master",
  "authorization_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/auth",
  "token_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/token",
  "introspection_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/token/introspect",
  "userinfo_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/userinfo",
  "end_session_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/logout",
  "jwks_uri": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/certs",
  "check_session_iframe": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/login-status-iframe.html",
  "grant_types_supported": [
    "authorization_code",
    "implicit",
    "refresh_token",
    "password",
    "client_credentials",
    "urn:ietf:params:oauth:grant-type:device_code",
    "urn:openid:params:grant-type:ciba"
  ],
  "response_types_supported": [
    "code",
    "none",
    "id_token",
    "token",
    "id_token token",
    "code id_token",
    "code token",
    "code id_token token"
  ],
  "subject_types_supported": [
    "public",
    "pairwise"
  ],
  "id_token_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512"
  ],
  "id_token_encryption_alg_values_supported": [
    "RSA-OAEP",
    "RSA-OAEP-256",
    "RSA1_5"
  ],
  "id_token_encryption_enc_values_supported": [
    "A256GCM",
    "A192GCM",
    "A128GCM",
    "A128CBC-HS256",
    "A192CBC-HS384",
    "A256CBC-HS512"
  ],
  "userinfo_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512",
    "none"
  ],
  "request_object_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512",
    "none"
  ],
  "response_modes_supported": [
    "query",
    "fragment",
    "form_post"
  ],
  "registration_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/clients-registrations/openid-connect",
  "token_endpoint_auth_methods_supported": [
    "private_key_jwt",
    "client_secret_basic",
    "client_secret_post",
    "tls_client_auth",
    "client_secret_jwt"
  ],
  "token_endpoint_auth_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512"
  ],
  "introspection_endpoint_auth_methods_supported": [
    "private_key_jwt",
    "client_secret_basic",
    "client_secret_post",
    "tls_client_auth",
    "client_secret_jwt"
  ],
  "introspection_endpoint_auth_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512"
  ],
  "claims_supported": [
    "aud",
    "sub",
    "iss",
    "auth_time",
    "name",
    "given_name",
    "family_name",
    "preferred_username",
    "email",
    "acr"
  ],
  "claim_types_supported": [
    "normal"
  ],
  "claims_parameter_supported": true,
  "scopes_supported": [
    "openid",
    "email",
    "roles",
    "profile",
    "web-origins",
    "offline_access",
    "address",
    "microprofile-jwt",
    "phone"
  ],
  "request_parameter_supported": true,
  "request_uri_parameter_supported": true,
  "require_request_uri_registration": true,
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ],
  "tls_client_certificate_bound_access_tokens": true,
  "revocation_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/revoke",
  "revocation_endpoint_auth_methods_supported": [
    "private_key_jwt",
    "client_secret_basic",
    "client_secret_post",
    "tls_client_auth",
    "client_secret_jwt"
  ],
  "revocation_endpoint_auth_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512"
  ],
  "backchannel_logout_supported": true,
  "backchannel_logout_session_supported": true,
  "device_authorization_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/auth/device",
  "backchannel_token_delivery_modes_supported": [
    "poll"
  ],
  "backchannel_authentication_endpoint": "http://test-oidc-keycloak:8080/auth/realms/master/protocol/openid-connect/ext/ciba/auth"
}

Access Token

https://jwt.io/ でデコードできる

JWT

eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJwSmdoalAxUVJLZ1lEWnFJVzNKV1dETnI3eUc5aEJiVGk4VV94SXh0Tmc4In0.eyJleHAiOjE2MjQ3NDc2MzIsImlhdCI6MTYyNDc0NzU3MiwiYXV0aF90aW1lIjoxNjI0NzQ3NTcxLCJqdGkiOiI2ZmU0NjkwNy1iZTFjLTQ2YWUtODlhYi03ZGIxMjI4YTJlMDYiLCJpc3MiOiJodHRwOi8vdGVzdC1vaWRjLWtleWNsb2FrOjgwODAvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImFjMDg0OGU4LTUzZTMtNDQ4My1hNzM5LWQ3NjIzMTdhZjQ0NCIsInR5cCI6IkJlYXJlciIsImF6cCI6InRlc3QiLCJub25jZSI6IlVudkUtWjhwUS13MmxPSUVyd2F2WDF4dEo4eXlCNlhhV0l4cjRMQmxiZzAiLCJzZXNzaW9uX3N0YXRlIjoiZDk2OTQyNzctMDFhNy00OWRjLWJlMDktNTRhMzg3MDY2ZDkxIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLW1hc3RlciIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJob2dlIn0.ETQpOLqEPvTSBfwts85YwDMen8tw8ZUeF21w5LqdBaVquS7DuNcQpI-A_4RM3OR2L3XuwIfMYLk3AmGObZz_4bY7d1yfeBJYNwXXS1A6VJDQU3kZdGr9VZPAUoHcoMD6R4EZbG4nCl_idJ0b_bg4WEeY5IjdNLjcxrZZ4fax0TpuvBIoRJmnOIKMsKg5W7HyJYZ8nqKxFw1a3aGV2sy5tqeyAYordAO7_T4pgt-WpH73IJFqT7mNXorEnNEROqZQR7FAqU4Rs2mFBynAN1Sq_ICB8avYzF9QkLrUmud7A5oFvCjVi2WWHNxhhkM6x7Gv7gjqwlsaEofp9awkjqfFew

Decoded-Payload

{
  "exp": 1625894396,
  "iat": 1625894336,
  "auth_time": 1625894336,
  "jti": "193cba26-dcba-4704-9d39-31f88ee8339b",
  "iss": "http://test-oidc-keycloak:8080/auth/realms/master",
  "aud": "account",
  "sub": "9e9e8079-e8c4-4eaa-baaf-bcd22707d9a7",
  "typ": "Bearer",
  "azp": "test",
  "nonce": "B-3iE7nRNtsVs4D0r7YZw88-PPwBsQDoDKpOxrN3o9o",
  "session_state": "ef353a37-809a-4945-b3f2-0d04d6d01e32",
  "acr": "1",
  "realm_access": {
    "roles": [
      "offline_access",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "openid profile email",
  "email_verified": false,
  "preferred_username": "hoge",
  "email": "aa@aa.com"
}

ID Token

JWT

eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJwSmdoalAxUVJLZ1lEWnFJVzNKV1dETnI3eUc5aEJiVGk4VV94SXh0Tmc4In0.eyJleHAiOjE2MjQ3NDc2MzIsImlhdCI6MTYyNDc0NzU3MiwiYXV0aF90aW1lIjoxNjI0NzQ3NTcxLCJqdGkiOiJjYjI3YmY1MC0zYmZjLTQxN2QtOWU1NS1jMzc4M2UyODFiMzEiLCJpc3MiOiJodHRwOi8vdGVzdC1vaWRjLWtleWNsb2FrOjgwODAvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoidGVzdCIsInN1YiI6ImFjMDg0OGU4LTUzZTMtNDQ4My1hNzM5LWQ3NjIzMTdhZjQ0NCIsInR5cCI6IklEIiwiYXpwIjoidGVzdCIsIm5vbmNlIjoiVW52RS1aOHBRLXcybE9JRXJ3YXZYMXh0Sjh5eUI2WGFXSXhyNExCbGJnMCIsInNlc3Npb25fc3RhdGUiOiJkOTY5NDI3Ny0wMWE3LTQ5ZGMtYmUwOS01NGEzODcwNjZkOTEiLCJhdF9oYXNoIjoiUlZadkNhaEdCYWk2TlVydkVKam9mZyIsImFjciI6IjEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6ImhvZ2UifQ.rMcNKLdfd64W0r9QIPIlXVIiyTi6MUhmAQX2H_Bp6eviEecRoPYHxawG5fXZS2iNKAzDL5OjHbGl_Yzxkjr2UPBB7UWfgVIcjfD3BiOQO-V4haa8O3gGPMx0Xm1LD6r5QVV6eARm5_FTvpO8xwmgVzW0KXRfn9M-HyofE4NEjsMQTAel8TY_U7H1KJsqTezEZRfHrtU7EwyO0OVRvfVXp58F9Ly5GtXNrMDlekQWdaTA222_Rk6Tm6h3KNgwUKwbigtBwMDK19ZXeJ94_sFcbHfKcbgnFhnzEYyZ-3rSM9SKtPh0JUlordUOU7FUQVqKxviOgwrj7Wqi-2kekBZnxg

Decoded JSON

{
  "exp": 1624747632,
  "iat": 1624747572,
  "auth_time": 1624747571,
  "jti": "cb27bf50-3bfc-417d-9e55-c3783e281b31",
  "iss": "http://test-oidc-keycloak:8080/auth/realms/master",
  "aud": "test",
  "sub": "ac0848e8-53e3-4483-a739-d762317af444",
  "typ": "ID",
  "azp": "test",
  "nonce": "UnvE-Z8pQ-w2lOIErwavX1xtJ8yyB6XaWIxr4LBlbg0",
  "session_state": "d9694277-01a7-49dc-be09-54a387066d91",
  "at_hash": "RVZvCahGBai6NUrvEJjofg",
  "acr": "1",
  "email_verified": false,
  "preferred_username": "hoge"
}

jwks_uri Keys

{
  "keys": [
    {
      "kid": "pJghjP1QRKgYDZqIW3JWWDNr7yG9hBbTi8U_xIxtNg8",
      "kty": "RSA",
      "alg": "RS256",
      "use": "sig",
      "n": "zSlLHc3Znj4mpnGyyxr32XgT-cCP4YPUCGxQ4s7yuplhAeePO2vUUytlx0oekP1M8xVa4fFsmv1VNkbj8iF6k_gmyRJAoBjA6CEiV7p42-nQcwSV6i_V-iyXKejKoH7PKAQZmhUsz21fNEWhpprRL3s3iGQS5EQpdJf_ACIbSWAvU2GxczFUxTReVGBSjwWrtqdC1N-qvyVFoD_1o1HKD0wGGIxJS3Bt4qvYKuxrpXb_5iaK1lSYXj8r2nwd2tgs7qe1WgTFDpvh_ncLPIkNf08OLsH7CxoDs-sPQvbKgufsU1vTFhh0fXi6Z1pheO1mTnncs6KgLy_nlC7JskPM2Q",
      "e": "AQAB",
      "x5c": [
        "MIICmzCCAYMCBgF6KFytNzANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjEwNjIwMDczODIwWhcNMzEwNjIwMDc0MDAwWjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNKUsdzdmePiamcbLLGvfZeBP5wI/hg9QIbFDizvK6mWEB5487a9RTK2XHSh6Q/UzzFVrh8Wya/VU2RuPyIXqT+CbJEkCgGMDoISJXunjb6dBzBJXqL9X6LJcp6Mqgfs8oBBmaFSzPbV80RaGmmtEvezeIZBLkRCl0l/8AIhtJYC9TYbFzMVTFNF5UYFKPBau2p0LU36q/JUWgP/WjUcoPTAYYjElLcG3iq9gq7Guldv/mJorWVJhePyvafB3a2Czup7VaBMUOm+H+dws8iQ1/Tw4uwfsLGgOz6w9C9sqC5+xTW9MWGHR9eLpnWmF47WZOedyzoqAvL+eULsmyQ8zZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIqK00VqPXHVl8gpybKsyyZCnz+w3HoFO+7c4pVtWHy7eREPdmY4pgyqWKyY4064J/ZJ7TK8JNs6tQf1/LZUmp6fRMXQVRJglJyGz/J4ZBg7kqmzxi9kroNRhcStMidYjEkUHhpTK3dIOfUZ4vaf/OfN3WE8JzsXG5Jxz7DY9wN3oUCeZf6/ju2Lb8gIKAq+7wmxhmkZEZNU21Rx9S6bz4mYMSFaEQ7ldg3y14doiCZYCeVSJSoq74uOdAv+kxdo/FsnGZT8GRKsvCwQMSYAe/l5ccHVceFK3Isxp2EZVNwD/6ytjMkUgUTibakJAGVJMouRZStiy2n2srQ2egDjKhA="
      ],
      "x5t": "HaBzJVfpnNV6jtIK9ZtDn0F7mYA",
      "x5t#S256": "VPN7LyGrZXA_gb6WBOkk-4pUWuzxxctuKAWtdm5mYzk"
    }
  ]
}

Userinfo

{
	"sub": "9e9e8079-e8c4-4eaa-baaf-bcd22707d9a7",
	"email_verified": false,
	"preferred_username": "hoge",
	"email": "aa@aa.com"
}