こんにちは。
アプリケーションサービス部、DevOps担当の兼安です。
本記事はこちらの記事の続きです。
今回は、バックエンドプログラムでJWT(JSON Web Token)を解析し、ユーザー情報を取得する方法を説明します。
- 本記事のターゲット
- 今回の題材
- JWT(JSON Web Token)とは
- Amazon CognitoにおけるJWT
- JWTとOpenID Connect(OIDC)
- Amazon Cognitoが発行するJWTの検証
- ALBを使用した場合の公開鍵の取得方法
- JWTからユーザー情報を取得するサンプルプログラム
- アプリケーションのデータベースとの連携
- 次回の内容
本記事のターゲット
Webアプリケーションの開発経験があり、今後、Webアプリケーションをスケーラブルにしたい方を対象としています。
記事中にロードバランサー(=ALB)やAmazon EC2などが出てきますが、これらの説明は割愛していますので、AWSのコンピューティングサービスやデータベースサービスの知識があることが前提となります。
今回の題材
Amazon Cognitoで認証すると、HTTPリクエストのヘッダーにJWT(JSON Web Token)が付与されます。
このJWTには、Amazon Cognitoで管理しているユーザー情報が含まれており、プログラムでこのJWTを解析することで、ユーザー情報を取得することができます。
JWTからユーザー情報を取得することで、Webアプリケーションのバックエンドプログラムで、ユーザー情報を利用した処理を行うことができます。
今回は、このJWTからユーザー情報を取得する方法を説明します。
JWT(JSON Web Token)とは
JWT(JSON Web Token)は、JSON形式を用いて二者間で安全に情報をやり取りするためのオープンスタンダードです。
主な用途は、認証情報のやり取りです。
Amazon CognitoにおけるJWT
こちらのページにある通り、Amazon CognitoはOpenID Connect(OIDC)仕様に基づいたJWTを発行し、認証情報をやり取りします。
Amazon Cognito は、OpenID Connect (OIDC) 仕様の整合性と機密性の一部を使用するトークンを発行します。
署名を比較することで、JWTの整合性を確認することができます。
悪意のあるユーザーがトークンを変更することがありますが、アプリケーションがパブリックキーを取得して署名を比較すれば、トークンは一致しなくなります。
JWTは、以下の3つの部分から構成されます。
| 項目 | 説明 |
|---|---|
| ヘッダ | トークンの種類や署名アルゴリズムなどのメタデータ |
| ペイロード | トークンに含まれる情報 |
| 署名 | トークンの整合性を確認するための署名 |
バックエンドプログラムでJWTからユーザー情報を取得する際には、ペイロードの情報を利用します。
JWTとOpenID Connect(OIDC)
AWS Cognitoのページを読んでいくと、OpenID Connect(OIDC)という言葉が出てきますので、こちらも説明しておきます。
OpenID Connect(以降、OIDCと略します)は、OAuth 2.0プロトコルをベースにした認証プロトコルです。
OAuthは認可を行うプロトコルであり、それに認証のプロセスを追加したものがOIDCです。
認証と認可の違いは前回の記事を参照してください。
OAuthの提供する認可の仕組みでは賄いきれない領域があり、それを補完するためにOAuthを拡張したのがOIDCです。
この辺りの詳細な話は、今回は割愛させていただきます。
OAuthは、認可の仕組みとしてアクセストークンとリフレッシュトークンを提供します。
OIDCは、OAuthに認証の仕組みを追加し、OAuthが提供するトークンに加えてIDトークンを提供します。
OIDCにおいて、トークンに用いられるのがJWTです。
本記事で述べているJWTからユーザー情報を取得するというのは、OIDCにおけるIDトークンからユーザー情報を取得するという意味になります。
なお、Amazon Cognitoからユーザー情報を取得する方法には、ユーザー属性エンドポイントを利用する方法もあります。
こちらは別の機会で触れるとして、本記事では対象外としています。
Amazon Cognitoが発行するJWTの検証
Amazon Cognitoが発行するJWTの検証は、以下の手順で行います。
- HTTPリクエストのヘッダーからJWTを取得
- JWTのヘッダー部分をデコードして、
kid(Key ID)を取得 kidを使って、公開鍵を取得- JWTのデコードと公開鍵を使った署名検証
詳細は以下のページを参照してください。
ALBを使用した場合の公開鍵の取得方法
この後サンプルプログラムを使ってJWTからユーザー情報を取得する方法を説明します。
本記事のサンプルプログラムは、前回に引き続き、ALBを使用した構成を想定しています。

ALBを使用した場合、公開鍵の取得URLは以下のようになります。
https://public-keys.auth.elb.region.amazonaws.com/key-id
ALBを使わない場合の公開鍵の取得URLは、上述のAWS公式ページを参照してください。
JWTからユーザー情報を取得するサンプルプログラム
以下のサンプルプログラムは、JWTからユーザー情報を取得するためのものです。
このサンプルプログラムは、PHPとLaravelを使用しています。
このサンプルコードgetCognitoPayloadは、JWTを解析してペイロードを取得するメソッドです。
ペイロードを取得することで、ユーザー情報を取得することができます。
下記サンプルプログラムでは、ペイロードをそのままレスポンスに返していますが、実際の運用では、このメソッドのreturnの部分を修正し、ペイロードをそのまま返して、ユーザー情報をどう抜き取るかは呼び出し側に任せるイメージです。
<?php namespace App\Http\Controllers; use Firebase\JWT\JWT; use Firebase\JWT\Key; use GuzzleHttp\Client; use Illuminate\Http\Request; require_once __DIR__ . '/../../../vendor/autoload.php'; abstract class Controller { /** * リクエストヘッダーからJWTを取得して解析するメソッド * コントローラーの基底クラスに実装して、他のコントローラーで継承して利用する想定 * @param Request $request HTTPリクエスト * @see https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/listener-authenticate-users.html * */ protected function getCognitoPayload(Request $request) { // Step 1: ALB から送られる JWT を取得 $encoded_jwt = $request->header('x-amzn-oidc-data'); if (!$encoded_jwt) { return response()->json(['error' => 'No JWT found in headers'], 400); } // Step 2: JWT のヘッダー部分をデコードして "kid" を取得 $jwt_headers = explode('.', $encoded_jwt); $jwt_head = json_decode(base64_decode(strtr($jwt_headers[0], '-_', '+/')), true); if (!isset($jwt_head['kid'])) { return response()->json(['error' => '"kid" not found in JWT headers'], 400); } $kid = $jwt_head['kid']; $region = 'ap-northeast-1'; // ALB のリージョン // Step 3: ALB の公開鍵を取得 $url = "https://public-keys.auth.elb.$region.amazonaws.com/$kid"; $client = new Client(); try { $response = $client->get($url); $pub_key = $response->getBody()->getContents(); } catch (\Exception $e) { return response()->json(['error' => 'Failed to fetch public key', 'message' => $e->getMessage()], 500); } // Step 4: JWTのデコードと公開鍵を使った署名検証 try { $decoded_payload = JWT::decode($encoded_jwt, new Key($pub_key, 'ES256')); // テストのため、取得したペイロードをそのままレスポンスに返しています // 実際の運用では、ペイロードをそのまま返して、ユーザー情報をどう抜き取るかは呼び出し側に任せるイメージです return response()->json($decoded_payload, 200, [], JSON_PRETTY_PRINT); } catch (\Exception $e) { return response()->json(['error' => 'JWT verification failed', 'message' => $e->getMessage()], 400); } } }
このプログラムで取得できるペイロードは、以下のような内容になります。
{ "sub": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "email": "satoshi.kaneyasu@serverworks.co.jp", "username": "kaneyasu", "exp": 1676316377, "iss": "https://cognito-idp.<Region>.amazonaws.com/<your user pool ID>" }
| 項目 | 説明 |
|---|---|
| sub | 認証されたユーザーの固有識別子 (UUID) またはサブジェクト |
| メールアドレス | |
| username | ユーザー名 |
| exp | ユーザーのトークンの有効期限が切れる有効期限 (Unix の時間形式) |
| iss | トークンを発行した ID プロバイダーのURL |
emailやusernameなどは、Amazon Cognitoでユーザープールに登録した属性情報です。

ユーザープールの属性情報は可変なので、必要に応じて追加・変更することができます。
増やした属性情報もペイロードに含めることができます。
従って、アプリケーションが権限制御に使用する情報を属性情報に追加してペイロードに含めるようにすれば、プログラム側はサインインしたユーザーに応じた処理に繋げることができます。
アプリケーションのデータベースとの連携
Amazon Cognitoが付与するJWTからユーザー情報を取得できます。
一方で、ユーザー情報はAmazon Cognitoのユーザープールだけに保存しておけばよいのでしょうか?
アプリケーションの一般的な実装では、ユーザー情報と他のデータを結合して利用します。
SQLで言うところのJOINですね。
私は結合をしやすくするためには、アプリケーションのデータベースにもユーザー情報が保存されていた方が便利だと思っています。
Amazon Cognitoを導入したからといって、データの結合方法まで変えるのは本意ではありません。
アプリケーションのデータベースにもユーザー情報が保存するとしたら、以下のようなテーブル定義になるかと思います。
(テーブルはPostgreSQLを想定しています)
CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- アプリ内のユーザーID(内部管理用) cognito_sub UUID NOT NULL UNIQUE, -- Cognitoのユーザー識別子(sub) email VARCHAR(255) NOT NULL UNIQUE, -- メールアドレス username VARCHAR(100) NOT NULL, -- ユーザー名 first_name VARCHAR(100), -- 名(オプション) last_name VARCHAR(100), -- 姓(オプション) phone_number VARCHAR(20) UNIQUE, -- 電話番号(オプション) user_class VARCHAR(50) DEFAULT 'GUEST', -- ユーザークラス(GUEST, ADMINなど) user_status VARCHAR(50) DEFAULT 'ACTIVE', -- ユーザーステータス(ACTIVE, DISABLEDなど) created_at TIMESTAMPTZ DEFAULT now(), -- 作成日時 updated_at TIMESTAMPTZ DEFAULT now() -- 更新日時 );
cognito_subは、JWTのペイロードに含まれるsubの値を保存するカラムです。
SQLで任意のデータとユーザー情報を結合する場合、以下の条件をつけるイメージです。
SELECT example_table.*, users.id, users.username, users.email FROM users INNER JOIN example_table ON users.id = example_table.user_id WHERE users.cognito_sub = 'JWTのペイロードから取得したsub';
次回の内容
今回は、プログラムでJWT(JSON Web Token)を解析し、ユーザー情報を取得する方法を説明しました。
後半では、アプリケーションのデータベースにもユーザー情報を保存する方式について説明しましたが、この方式はいわばユーザー情報の二重管理です。
アプリケーションのデータベースとAmazon Cognitoでユーザー情報を同期させる実装方法を解説します。
兼安 聡(執筆記事の一覧)
アプリケーションサービス部 DS3課所属
2025 Japan AWS Top Engineers (AI/ML Data Engineer)
2025 Japan AWS All Certifications Engineers
2025 AWS Community Builders
Certified ScrumMaster
PMP
広島在住です。今日も明日も修行中です。
X(旧Twitter)