投稿日
Amazon Cognitoが発行するトークンへClientMetadataを使って動的な情報を埋め込む方法
もくじ
はじめに
Amazon Cognito(以下Cognito)による認証では、IDトークンやアクセストークンに、認証時の状況やユーザーの選択に応じて変化する動的な情報を含めたい場合があります。
たとえば、アクセス元デバイスの種別や、ログイン時にユーザーが選択した操作対象の組織などが挙げられます。
氏名や所属組織などの固定情報はCognitoのユーザー属性として管理できますが、認証ごとに切り替わる情報はユーザー属性では扱うことができません。
動的な情報をトークンに含めるには、クライアントがClientMetadataでCognitoに情報を渡し、Cognitoがトークン生成前Lambdaを経由してその情報をトークンに追加する必要があります。
本記事では、この方法について、実装例を交えながら解説します。
想定読者
- Cognitoを使用した認証(特にSRP認証、カスタム認証)についての基礎知識がある方
- Cognitoが発行するトークンに動的な情報を埋め込みたい方
前提条件・環境情報
本記事のサンプルコードは、以下の環境で動作確認しています。
クライアント側(C#)
| 項目 | バージョン |
| .NET | 10.0 |
| Amazon.Extensions.CognitoAuthentication | 3.1.4 |
| AWSSDK.CognitoIdentityProvider | 4.0.6.2 |
| System.IdentityModel.Tokens.Jwt | 8.3.1 |
Lambda関数(JavaScript)
| 項目 | 設定値 |
| ランタイム | Node.js 24.x |
| アーキテクチャ | x86_64 |
ClientMetadataとは
概要
ClientMetadataは、クライアントからCognitoのAPIを呼び出す際、任意の追加情報をキーと値のペアで指定できるパラメータです。
この情報は認証フローの中でLambdaトリガーに渡すことができ、トークンや認証処理のカスタマイズに利用できます。
var clientMetadata = new Dictionary<string, string>
{
{ "organizationId", "org-12345" },
{ "userRole", "admin" }
};
制約
ClientMetadataをトークン生成前Lambdaに渡すには、Cognitoの特定の認証APIを使用する必要があります。
ClientMetadataの受け渡しは、以下の2段階で行われます。
- ステップ1:クライアントからCognitoへの送信
どの認証APIでもClientMetadataをCognitoに送ることができます。 - ステップ2:Cognitoからトークン生成前Lambdaへの送信
トークン生成前LambdaにClientMetadataが伝わるかどうかは、ステップ1でどの認証APIで渡したかによって異なります。

ステップ1でInitiateAuth APIでClientMetadataを渡した場合、ステップ2でClientMetadataはトークン生成前Lambdaに届きません。
トークン生成前LambdaにClientMetadataを渡すには、RespondToAuthChallenge APIでClientMetadataを付与してCognitoを呼び出す必要があります。
(参考:Amazon Cognito の Lambda トリガーにClientMetadataを渡す | AWS re:Post)
| API | トークン生成前Lambdaに届くかどうか |
| InitiateAuth API | 届かない |
| RespondToAuthChallenge API | 届く |
※InitiateAuth APIでCognitoにClientMetadataを渡した場合、サインアップ前Lambda、認証前Lambda、ユーザー移行Lambdaに届けることができます。
※管理者権限で呼び出すAdmin API(AdminInitiateAuth API、AdminRespondToAuthChallenge API)もありますが、本記事ではユーザー権限で呼び出す非Admin API(InitiateAuth API、RespondToAuthChallenge API)を使用します。
パターン1:SRP認証(USER_SRP_AUTH)
概要
SRP(Secure Remote Password)認証は、Cognitoが標準で提供する安全な認証方式です。
SRP認証では必ずRespondToAuthChallenge APIが呼ばれるため、ClientMetadataをトークン生成前Lambdaに渡すことができます。
認証フロー開始時に呼び出すInitiateAuth APIでもClientMetadataを指定できますが、トークン生成前Lambdaには届きません。
トークン生成前Lambdaで利用できるのは、RespondToAuthChallenge APIで渡したClientMetadataのみです。
認証フロー
- InitiateAuth(USER_SRP_AUTH)
クライアントがSRP_Aとユーザー名を送信してSRP認証を開始します。
この時点でClientMetadataを渡すことができますが、トークン生成前Lambdaには届きません。 - PASSWORD_VERIFIERチャレンジ
CognitoがSalt等を含んだチャレンジをクライアントに返却します。 - RespondToAuthChallenge(PASSWORD_VERIFIER)
クライアントがパスワードと受け取った値から暗号学的証明(署名)を計算して送信します。
この時点で渡したClientMetadataはトークン生成前Lambdaに届きます。 - Cognito認証判定
Cognitoが送信された署名を検証し、認証の成否を判定します。 - トークン生成前Lambda呼び出し
認証成功後、トークン発行前にトークン生成前Lambdaが呼び出されます。
RespondToAuthChallengeで渡したClientMetadataはここで利用できます。 - トークン発行
トークン生成前Lambdaで追加されたカスタムクレームを含むトークンが発行されます。

サンプル実装
トークン生成前Lambda(JavaScript)
AWS Lambdaコンソールで新しい関数を作成し、下記のコードをデプロイします。
/**
* Pre Token Generation Lambda(V2.0)
*
* ClientMetadataの内容をトークンのカスタムクレームに追加します。
*/
export const handler = async (event) => {
console.log("Pre Token Generation Event:", JSON.stringify(event, null, 2));
console.log("Trigger Source:", event.triggerSource);
console.log("ClientId:", event.callerContext.clientId);
// ClientMetadataを取得
let clientMetadata = event.request.clientMetadata || {};
console.log("Client Metadata:", JSON.stringify(clientMetadata, null, 2));
// トリガーバージョンがV2.0の場合
if (event.version === "2") {
event.response = {
claimsAndScopeOverrideDetails: {
idTokenGeneration: {
claimsToAddOrOverride: {
"customKey1": clientMetadata.customKey1
}
},
accessTokenGeneration: {
claimsToAddOrOverride: {
"customKey1": clientMetadata.customKey1
}
}
}
};
}
return event;
};
このLambda関数を、Cognito User Poolでトークン生成前トリガーとして設定します。
その際、トリガーイベントバージョンはV2.0を選択してください。V2.0では、IDトークンとアクセストークンに属性を追加できます。
動作確認
クライアント側(C#)
Amazon.Extensions.CognitoAuthentication SDKを使用すると、SRP認証の複雑な計算が自動化されるため、開発者は内部処理を意識することなく簡単に認証処理を実装できます。
StartWithSrpAuthAsyncでRespondToAuthChallengeを呼び出しています。
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;
using System.IdentityModel.Tokens.Jwt;
using Amazon.Extensions.CognitoAuthentication;
using Amazon.Runtime;
class Program
{
static async Task Main()
{
var clientId = "XXXXXXXX"; // Cognito User PoolのApp Client IDを指定
var userPoolId = "XXXXXXXX"; // Cognito User Pool IDを指定
Console.WriteLine("=== Amazon Cognito デモ ===");
await CustomSRPAuth(clientId, userPoolId);
}
static async Task CustomSRPAuth(string clientId, string userPoolId)
{
Console.Write("ユーザー名を入力してください: ");
var userName = Console.ReadLine();
Console.Write("パスワードを入力してください: ");
var password = Console.ReadLine();
// ClientMetadataを準備(トークンに埋め込みたい情報)
var clientMetadata = new Dictionary<string, string>
{
{ "customKey1", "customValue1" }
};
var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), FallbackRegionFactory.GetRegionEndpoint());
var userPool = new CognitoUserPool(userPoolId, clientId, provider);
var user = new CognitoUser(userName, clientId, userPool, provider);
var authRequest = new InitiateSrpAuthRequest
{
Password = password,
ClientMetadata = clientMetadata // トークンに埋め込みたい情報
};
// SDK内部で自動的にRespondToAuthChallenge APIが呼び出される
AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
// 認証成功
if (authResponse.AuthenticationResult != null)
{
Console.WriteLine("n認証成功!トークンを取得しました。");
DisplayTokenInfo(authResponse.AuthenticationResult);
return;
}
Console.WriteLine("n認証に失敗しました。");
}
static void DisplayTokenInfo(AuthenticationResultType authResult)
{
Console.WriteLine("n========== トークン情報 ==========");
// IDトークンの情報を表示
if (!string.IsNullOrEmpty(authResult.IdToken))
{
Console.WriteLine("n【IDトークンの属性情報】");
var idTokenHandler = new JwtSecurityTokenHandler();
var idToken = idTokenHandler.ReadJwtToken(authResult.IdToken);
Console.WriteLine($"発行者 (Issuer): {idToken.Issuer}");
Console.WriteLine($"対象者 (Audience): {string.Join(", ", idToken.Audiences)}");
Console.WriteLine($"発行日時: {idToken.ValidFrom}");
Console.WriteLine($"有効期限: {idToken.ValidTo}");
Console.WriteLine($"nクレーム数: {idToken.Claims.Count()}");
Console.WriteLine("nクレーム(属性情報):");
foreach (var claim in idToken.Claims)
{
Console.WriteLine($" {claim.Type}: {claim.Value}");
}
}
// アクセストークンの情報を表示
if (!string.IsNullOrEmpty(authResult.AccessToken))
{
Console.WriteLine("n【アクセストークンの属性情報】");
var accessTokenHandler = new JwtSecurityTokenHandler();
var accessToken = accessTokenHandler.ReadJwtToken(authResult.AccessToken);
Console.WriteLine($"発行者 (Issuer): {accessToken.Issuer}");
Console.WriteLine($"発行日時: {accessToken.ValidFrom}");
Console.WriteLine($"有効期限: {accessToken.ValidTo}");
Console.WriteLine($"nクレーム数: {accessToken.Claims.Count()}");
Console.WriteLine("nクレーム(属性情報):");
foreach (var claim in accessToken.Claims)
{
Console.WriteLine($" {claim.Type}: {claim.Value}");
}
}
// リフレッシュトークンの情報を表示(リフレッシュトークンはJWTではないため、存在確認のみ)
if (!string.IsNullOrEmpty(authResult.RefreshToken))
{
Console.WriteLine("n【リフレッシュトークン】");
Console.WriteLine($"リフレッシュトークンが発行されました(長さ: {authResult.RefreshToken.Length} 文字)");
}
Console.WriteLine("n===================================n");
}
}
実行結果
発行されたIDトークン、アクセストークン共に、「customKey1: customValue1」という属性が追加されていることが分かります。
=== Amazon Cognito デモ ===
ユーザー名を入力してください: testuser
パスワードを入力してください: xxxxxxxx
認証成功!トークンを取得しました。
========== トークン情報 ==========
【IDトークンの属性情報】
発行者 (Issuer): https://cognito-idp.ap-northeast-1.amazonaws.com/xxxxxxxx
対象者 (Audience): xxxxxxxxxxxxxxxxxxxxxxxxxx
発行日時: 0001/01/01 0:00:00
有効期限: 2026/06/23 1:39:55
クレーム数: 11
クレーム(属性情報):
origin_jti: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
sub: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
aud: xxxxxxxxxxxxxxxxxxxxxxxxxx
token_use: id
customKey1: customValue1 ←追加した属性
auth_time: 1782175195
iss: https://cognito-idp.ap-northeast-1.amazonaws.com/xxxxxxxx
cognito:username: testuser
exp: 1782178795
iat: 1782175195
jti: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
【アクセストークンの属性情報】
発行者 (Issuer): https://cognito-idp.ap-northeast-1.amazonaws.com/xxxxxxxx
発行日時: 0001/01/01 0:00:00
有効期限: 2026/06/23 1:39:55
クレーム数: 12
クレーム(属性情報):
sub: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
iss: https://cognito-idp.ap-northeast-1.amazonaws.com/xxxxxxxx
client_id: xxxxxxxxxxxxxxxxxxxxxxxxxx
origin_jti: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
token_use: access
customKey1: customValue1 ←追加した属性
scope: aws.cognito.signin.user.admin
auth_time: 1782175195
exp: 1782178795
iat: 1782175195
jti: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
username: testuser
【リフレッシュトークン】
リフレッシュトークンが発行されました(長さ: 1664 文字)
===================================
パターン2:カスタム認証(CUSTOM_AUTH)
概要
カスタム認証フロー(CUSTOM_AUTH)でも、RespondToAuthChallenge APIでClientMetadataを渡すことで、トークンにカスタム情報を追加できます。
この方法は、OTP認証やパスワードレス認証など独自認証フローを実装する場合に有効です。
必要なLambda関数
カスタム認証フローを使ってClientMetadataで受け渡した情報をトークンに埋め込む場合、以下の4つのLambda関数が必要です。
- カスタム認証用
- 認証チャレンジ定義Lambda
- 認証チャレンジ作成Lambda
- 認証チャレンジレスポンス確認Lambda
- トークンカスタマイズ用
- トークン生成前Lambda(パターン1:SRP認証で作成したものと同一)
カスタム認証用のLambdaで認証が完了した後、トークンを発行する直前にトークン生成前Lambdaが呼び出されます。
RespondToAuthChallenge APIでClientMetadataを渡し、トークン生成前Lambdaでカスタムクレームを追加する流れはパターン1:SRP認証の場合と同じため、サンプル実装と動作確認は省略します。
なお、RespondToAuthChallenge APIで渡したClientMetadataは、認証チャレンジ定義Lambda、認証チャレンジ作成Lambda、認証チャレンジレスポンス確認Lambdaでも参照可能です。
一方、認証フロー開始時に呼び出すInitiateAuth APIで渡したClientMetadataは、これらのLambdaでは利用できません。
認証フロー
- InitiateAuth(CUSTOM_AUTH)
クライアントがカスタム認証を開始します。
この時点でClientMetadataを渡すことができますが、トークン生成前Lambdaには届きません。 - 認証チャレンジ定義Lambda(1回目)
認証フローを定義するLambdaが呼ばれ、次に実行するチャレンジを決定します。 - 認証チャレンジ作成Lambda
チャレンジを生成します。 - CUSTOM_CHALLENGEレスポンス
Cognitoがチャレンジ内容をクライアントに返却します。 - RespondToAuthChallenge(CUSTOM_CHALLENGE)
クライアントがチャレンジへの回答を送信します。
この時点でClientMetadataを渡すと、トークン生成前Lambdaに届きます。 - 認証チャレンジレスポンス確認Lambda
クライアントの回答を検証します。 - 認証チャレンジ定義Lambda(2回目)
検証結果を受けて、認証完了かさらにチャレンジを続けるかを判定します。 - トークン生成前Lambda呼び出し
認証完了後、トークン発行前にトークン生成前Lambdaが呼び出されます。
RespondToAuthChallengeで渡したClientMetadataがここで利用可能になります。 - トークン発行
トークン生成前Lambdaで追加されたカスタムクレームを含むトークンが発行されます。

参考:パスワード認証(USER_PASSWORD_AUTH)でClientMetadataが届かない理由
パスワード認証(USER_PASSWORD_AUTH)では、通常はInitiateAuth APIのみで認証が完了します。
この場合、RespondToAuthChallenge APIは呼ばれないため、ClientMetadataはトークン生成前Lambdaに届きません。
ただし、多要素認証(MFA)など認証チャレンジが発生した場合は、RespondToAuthChallenge APIが呼び出されるため、ClientMetadataをトークン生成前Lambdaに渡すことができます。
認証フロー
- InitiateAuth(USER_PASSWORD_AUTH)
クライアントがユーザー名とパスワードを平文でCognitoに送信します。
ClientMetadataも渡すことができますが、トークン生成前Lambdaには届きません。 - Cognito認証判定
Cognitoがユーザー名とパスワードを検証します。 - トークン生成前Lambda呼び出し
認証成功後、トークン発行前にトークン生成前Lambdaが呼び出されます。
しかし、InitiateAuthで渡したClientMetadataはここでは利用できません。 - トークン発行
カスタムクレームを追加できないままトークンが発行されます。

おわりに
参考資料
-
- InitiateAuth – Amazon Cognitoユーザープール
- Amazon Cognito の Lambda トリガーにClientMetadataを渡す | AWS re:Post
- トークン生成前の Lambda トリガー
- 認証フロー – Amazon Cognito
- カスタム認証チャレンジの Lambda トリガー – Amazon Cognito
- aws/aws-sdk-net-extensions-cognito: An extension library to assist in the Amazon Cognito User Pools authentication process
- AWS-Black-Belt_2026_Amazon-Cognito-Basic_0430_v1.pdf
- AWS-Black-Belt_2026_Amazon-Cognito-Advanced_0430_v1.pdf
