この記事は「2026 Japan AWS Jr.Champions 真夏のQiitaリレー」の31日目の記事となります。(8月最終日ですが、リレーは9月以降も続きます!!)
過去の投稿(リンク集)は以下リンクからご覧ください。
はじめに
Amazon Cognitoは、ユーザー登録やログイン、認証・認可、トークン発行といった処理をマネージドに提供するサービスです。
Cognitoを用いたユーザー登録やログイン、トークン発行などのタイミングに独自処理を行いたい場合は、Lambdaトリガーを利用することが可能です。
本記事では、Lambdaトリガーの種類や設定方法、具体的なユースケース、実装例を整理し、Cognitoの標準機能だけでは実現できない独自処理をどのように実装できるかを整理します。
Lambdaトリガーには様々な種類があり、すべてを1つの記事で扱うと内容が非常に多くなるため、本記事では基本的なLambdaトリガーを中心に整理します。
カスタム認証やユーザー移行など、応用的なLambdaトリガーについては応用編として別の記事で紹介します。
1.Lambdaトリガーとは
Lambdaトリガーは、Cognitoで発生したイベントを契機にLambdaを実行し、認証・ユーザー登録などの処理をカスタマイズする仕組みです。
例えばユーザー登録の場合、次のような流れになります。
ユーザー
│ 1. サインアップをリクエスト
▼
Amazon Cognito
│ 2. Lambdaトリガーを呼び出す
▼
Lambda
│ 3. 登録可否のチェックなどを実行
▼
Amazon Cognito
│ 4. チェック結果に基づいて登録処理
▼
ユーザー登録完了
CognitoからLambdaへは次のようなJSON形式のeventが渡されます。
{
"version": "1",
"triggerSource": "PreSignUp_SignUp",
"region": "ap-northeast-1",
"userPoolId": "ap-northeast-1_xxxxx",
"userName": "user@example.com",
"callerContext": {
"clientId": "xxxxxxxx"
},
"request": {
"userAttributes": {
"email": "user@example.com"
}
},
"response": {}
}
Lambdaはこのeventを確認・編集し、Cognitoへ返します。Cognitoは返却された内容を利用して後続処理を続けます。Lambdaがエラーを返すと対象のサインアップや確認処理が失敗となります。
def lambda_handler(event, context):
# 独自処理
return event
2.Lambdaトリガー利用時の注意点
2.1. 5秒以内に応答する
多くのCognito Lambdaトリガー(Custom sender以外)は、5秒以内に応答する必要があります。この時間は変更できません。
外部APIの呼び出しや時間のかかるDB処理は、Amazon SQSなどを利用し、別のLambdaで処理することも検討します。
Amazon Cognito
↓
Lambda
↓
Amazon SQS
↓
後続のLambda
2.2. 呼び出された理由に応じて処理を分岐
1つのLambdaトリガーが、複数の操作をきっかけに呼び出される場合があります。
例えば、Post confirmationトリガーは、ユーザー登録の確認後だけでなく、パスワード再設定の確認後にも呼び出されます。
どの操作をきっかけに呼び出されたかは、triggerSourceの値で確認できます。Post confirmationトリガーでは次のような値が設定されます。
-
PostConfirmation_ConfirmSignUp
ユーザー登録の確認完了時の値 -
PostConfirmation_ConfirmForgotPassword
パスワード再設定完了時の値
操作に応じて実行する内容を変えたい場合は、triggerSourceの値を確認して処理を分けます。
3.Lambdaトリガー一覧
2026年8月時点で、Cognito User Poolsでは以下のLambdaトリガーを利用できます。
| 分類 | Lambdaトリガー | 主な用途 |
|---|---|---|
| ユーザー登録 | Pre sign-up | 登録可否の判定、自動確認 |
| ユーザー登録 | Post confirmation | 登録確認・パスワード再設定確認後の処理 |
| 認証 | Pre authentication | ログイン直前の独自チェック |
| 認証 | Post authentication | ログイン成功後の処理 |
| カスタム認証 | Define Auth Challenge | 認証チャレンジの流れを決定 |
| カスタム認証 | Create Auth Challenge | 認証チャレンジを生成 |
| カスタム認証 | Verify Auth Challenge Response | 回答を検証 |
| トークン | Pre token generation | JWTのクレーム・スコープ変更 |
| ユーザー移行 | Migrate user | 既存認証基盤からCognitoへの移行 |
| メッセージ | Custom message | Cognitoが送るメール・SMSの内容変更 |
| メッセージ | Custom email sender | メール送信処理そのものをカスタマイズ |
| メッセージ | Custom SMS sender | SMS送信処理そのものをカスタマイズ |
| フェデレーション | Inbound federation | 外部IdPから受け取った属性を変換 |
本記事では、この中でも比較的利用する機会が多いと考えられる以下のLambdaトリガーについて整理します。
- Pre sign-up
- Post confirmation
- Pre authentication
- Post authentication
- Pre token generation
- Custom message
4.Lambdaトリガーの設定方法
Lambdaトリガーの設定方法詳細
4.1.CloudFormationから設定
以下は、Amazon CognitoユーザープールにPreSignUpとPostConfirmationの2つのLambdaトリガーを設定する例です。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
PreSignUpFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: sample-cognito-pre-sign-up
Runtime: python3.13
Handler: index.lambda_handler
Role: !GetAtt LambdaExecutionRole.Arn
Timeout: 5
Code:
ZipFile: |
def lambda_handler(event, context):
# 必要に応じてサインアップ可否の検証や属性変更を行う
return event
PostConfirmationFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: sample-cognito-post-confirmation
Runtime: python3.13
Handler: index.lambda_handler
Role: !GetAtt LambdaExecutionRole.Arn
Timeout: 5
Code:
ZipFile: |
def lambda_handler(event, context):
# 必要に応じてユーザー確認完了後の処理を行う
return event
UserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: sample-user-pool
LambdaConfig:
PreSignUp: !GetAtt PreSignUpFunction.Arn
PostConfirmation: !GetAtt PostConfirmationFunction.Arn
PreSignUpInvokePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt PreSignUpFunction.Arn
Principal: cognito-idp.amazonaws.com
SourceAccount: !Ref AWS::AccountId
SourceArn: !GetAtt UserPool.Arn
PostConfirmationInvokePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt PostConfirmationFunction.Arn
Principal: cognito-idp.amazonaws.com
SourceAccount: !Ref AWS::AccountId
SourceArn: !GetAtt UserPool.Arn
ポイント
-
AWS::Cognito::UserPoolのLambdaConfigに、利用するトリガーとLambda関数のARNを設定 - 複数のトリガーは
LambdaConfig配下に並べて指定可能 - Lambda関数ごとに
AWS::Lambda::Permissionを定義し、Cognitoからの実行を許可 -
SourceAccountとSourceArnを指定し、呼び出し元を対象のAWSアカウントとユーザープールに限定 - Lambdaトリガーは5秒以内に応答する必要があるため、Lambdaの
Timeoutは5秒以下に設定 - トリガーを削除する場合は、Lambda関数を削除する前に
LambdaConfigと対応するAWS::Lambda::Permissionを削除
4.2.AWSマネジメントコンソールから設定
Lambdaトリガーはコンソールからも設定できます。
Amazon Cognito
↓
ユーザープール
↓
対象のユーザープール
↓
拡張機能
↓
Lambdaトリガー
↓
Lambdaトリガーを追加
「トリガータイプ」と「Lambda関数」を選択し、保存します。
AWSマネジメントコンソールからLambdaトリガーを設定した場合、CognitoからLambda関数を呼び出すためのリソースベースポリシーは自動的に追加されます。
なお、カスタムメール送信者とカスタムSMS送信者はコンソールから設定できません。
5.代表的なLambdaトリガー
5.1. Pre sign-up
① 概要と目的
ユーザー情報がCognitoへ登録される直前に実行されるLambdaトリガーです。
登録情報を確認し、以下処理を行えます。
- 登録を許可する
- 登録を拒否する
- ユーザーを自動確認する
- メールアドレスを自動検証済みにする
② 具体的なユースケース
例えば社内システムで、
@example.com
のメールアドレスを持つユーザーだけ登録可能にするケースです。
SignUp
↓
Pre Sign-up
↓
メールドメイン確認
↓
OK → 登録
NG → 登録拒否
③ サンプルコード
def lambda_handler(event, context):
email = event["request"]["userAttributes"].get("email", "")
if not email.endswith("@example.com"):
raise Exception("このメールアドレスでは登録できません")
event["response"]["autoConfirmUser"] = True
event["response"]["autoVerifyEmail"] = True
return event
autoConfirmUserやautoVerifyEmailを利用すると、ユーザー確認やメール検証を自動化できます。
5.2. Post confirmation
① 概要と目的
ユーザーのサインアップ確認完了後やパスワード再設定確認後に実行されます。
ユーザー登録後に、以下処理を行えます。
- アプリケーションDBへユーザー情報を作成
- ウェルカムメールを送信
- 外部サービスへユーザーを連携
- 初期データを作成
② 具体的なユースケース
例えば、Cognitoへの登録完了後にアプリケーション側のDBにもユーザーを作成します。
Cognito登録完了
↓
Post confirmation
↓
SQS
↓
後続処理用 Lambda
↓
アプリDB登録
重い処理を直接実行するのではなく、SQSへメッセージを送信して後続処理を非同期化する構成です。
③ サンプルコード
import json
import os
import boto3
sqs = boto3.client("sqs")
def lambda_handler(event, context):
if event["triggerSource"] == "PostConfirmation_ConfirmSignUp":
attributes = event["request"]["userAttributes"]
sqs.send_message(
QueueUrl=os.environ["QUEUE_URL"],
MessageBody=json.dumps({
"userId": attributes["sub"],
"email": attributes.get("email")
})
)
return event
同じPost confirmationでもユーザー登録確認とパスワード再設定確認など複数の呼び出し元が存在するため、triggerSourceを確認して処理を分けることが重要です。
5.3. Pre authentication
① 概要と目的
ユーザーログイン時の認証処理前に実行されるトリガーです。
ログインするユーザーの情報を確認し、以下処理を行えます。
- アカウントの利用停止状態の確認
- 利用開始日前のログイン拒否
- 契約状態やサブスクリプション状態の確認
- 特定のApp Clientやログイン経路からのアクセス制限
② 具体的なユースケース
例えばユーザー属性に、
custom:login_disabled = true
が設定されているアカウントのログインを禁止します。
また、
custom:available_from = 2026-09-01
のように利用開始日を設定し、利用開始日前のログインを禁止することもできます。
ログイン要求
↓
Pre authentication
↓
属性・利用開始日を確認
├─ 条件を満たす
│ ↓
│ ログイン成功・トークン発行
│
└─ 条件を満たさない
↓
ログイン拒否
標準的なパスワード認証フローに追加して、
このユーザーを現在ログインさせてもよいか
という業務的な判定を実装できます。
③ サンプルコード
from datetime import date
def lambda_handler(event, context):
attributes = event["request"]["userAttributes"]
if attributes.get("custom:login_disabled") == "true":
raise Exception("現在このアカウントではログインできません")
available_from = attributes.get("custom:available_from")
if available_from and date.today() < date.fromisoformat(available_from):
raise Exception("このアカウントはまだ利用開始日前です")
return event
5.4. Post authentication
① 概要と目的
ユーザー認証が成功した後、トークンがユーザーへ発行される前に実行されます。
認証の可否やトークン内容を変更するためではなく、ログイン成功後の後処理実行に適しています。
例えば、以下のような処理を実装できます。
- CloudWatch Logsや監査基盤へのログイン履歴の記録
- アプリケーションDBの最終ログイン日時の更新
- 新しい端末や通常と異なるログインの検知・通知
- 外部の分析基盤やセキュリティ監視サービスへのログインイベント連携
- ユーザーごとのログイン回数や利用状況の集計
② 具体的なユースケース
例えばログイン監査ログをCloudWatch Logsへ記録します。
ログイン成功
↓
Post authentication
↓
監査ログ記録
↓
トークン発行
③ サンプルコード
import json
def lambda_handler(event, context):
print(json.dumps({
"event": "LOGIN_SUCCESS",
"userPoolId": event["userPoolId"],
"userName": event["userName"],
"clientId": event["callerContext"]["clientId"],
"newDeviceUsed": event["request"].get("newDeviceUsed")
}))
return event
5.5. Pre token generation
① 概要と目的
Cognitoが新しいIDトークンまたはアクセストークンを生成する直前に実行されるトリガーです。
IDトークンやアクセストークンに含めるクレーム、ユーザーグループ、IAMロール、アクセストークンのスコープを、認証時に動的に追加・変更・抑制できます。
例えば、以下のような処理を実装できます。
- テナントID、病院ID、組織IDなどをJWTのクレームとして追加する
- 契約プラン、ユーザーロール、所属組織などをクレームとして追加する
- テナントや利用する組織に応じてアクセストークンのスコープを追加・抑制する
- ユーザーグループやIAMロール情報を動的に上書きする
主な実行タイミングは次のとおりです。
| タイミング | triggerSource |
|---|---|
| 通常のユーザー認証完了後 | TokenGeneration_Authentication |
| リフレッシュトークンによるトークン更新時 | TokenGeneration_RefreshTokens |
| 仮パスワードを恒久パスワードへ変更した後 | TokenGeneration_NewPasswordChallenge |
② 具体的なユースケース
医療機関向けのマルチテナントシステムでは、1人の医師が複数の病院で同じシステムを利用する場合があります。
この場合、病院ごとにCognitoアカウントを作成するのではなく、医師は1つのCognitoアカウントで認証します。ログイン時に利用する病院を選択し、その病院IDをJWTのクレームとして追加します。
医師がログイン
↓
利用する病院を選択
↓
RespondToAuthChallenge(カスタム認証)
↓
ClientMetadataで病院IDを渡す
↓
カスタム認証成功
↓
Pre token generation
↓
active_hospital_idをJWTに追加
↓
IDトークン・アクセストークンを発行
例えば、医師がログイン時に利用する病院としてhospital-bを選択した場合、発行されるトークンには、次のように現在利用中の病院を示すクレームを追加できます。
{
"sub": "doctor-123",
"email": "doctor@example.com",
"active_hospital_id": "hospital-b"
}
API側ではactive_hospital_idを利用して、現在選択中の病院に属するデータだけを操作します。
active_hospital_id = hospital-b
↓
hospital-bのデータだけを検索・操作する
これにより、医師は同じCognitoアカウントを使いながら、ログインごとに利用する病院を切り替えられます。
③ サンプルコード
以下は、ログイン時に選択した病院IDをactive_hospital_idクレームとして、IDトークンとアクセストークンに追加する例です。
def lambda_handler(event, context):
client_metadata = event["request"].get("clientMetadata", {})
active_hospital_id = client_metadata.get("active_hospital_id")
id_token_claims = {}
access_token_claims = {}
if active_hospital_id:
id_token_claims["active_hospital_id"] = active_hospital_id
access_token_claims["active_hospital_id"] = active_hospital_id
event["response"] = {
"claimsAndScopeOverrideDetails": {
"idTokenGeneration": {
"claimsToAddOrOverride": id_token_claims
},
"accessTokenGeneration": {
"claimsToAddOrOverride": access_token_claims
}
}
}
return event
今回は、ログイン時に利用する病院をユーザーが選択し、その病院IDをトークンへ反映するため、カスタム認証を利用します。
カスタム認証チャレンジへの回答時に、選択した病院IDをClientMetadataとしてCognitoへ渡し、Pre token generationでJWTのクレームへ追加します。
④ イベントバージョンについて
イベントバージョンは、CognitoからLambdaに渡されるイベント形式と、Lambdaが変更できるトークンの範囲を決める設定です。
User PoolのPreTokenGenerationConfig.LambdaVersionで指定します。
| バージョン | 対象 |
|---|---|
V1_0 |
IDトークンのクレーム |
V2_0 |
ユーザー認証時のIDトークンとアクセストークンのクレーム・スコープ |
V3_0 |
V2_0の対象に加え、M2M認証時のアクセストークン |
本例では、IDトークンとアクセストークンの両方へactive_hospital_idを追加するため、V2_0を使用します。
V3_0は、M2Mのクライアント認証情報フローで発行するアクセストークンもカスタマイズする場合に使用します。M2M認証ではIDトークンは発行されません。
5.6. Custom message
① 概要と目的
Cognitoが送信するメールやSMSの本文・件名などを動的に変更するためのトリガーです。
対象は以下の通りです。
- ユーザー登録確認
- パスワードリセット
- MFA
- メールアドレス変更
- 確認コード再送信
② 具体的なユースケース
例えばユーザー登録時だけ、以下のような独自メッセージへ変更します。
○○サービスへようこそ。
確認コード:123456
ユーザー登録時の通知をカスタマイズする際の全体フローは、次のとおりです。
ユーザー登録
↓
Custom message
↓
カスタマイズしたメールを送信
↓
確認コードを入力
③ サンプルコード
def lambda_handler(event, context):
if event["triggerSource"] == "CustomMessage_SignUp":
code = event["request"]["codeParameter"]
event["response"]["emailSubject"] = "ユーザー登録の確認"
event["response"]["emailMessage"] = (
"ご登録ありがとうございます。<br>"
f"確認コードは <strong>{code}</strong> です。"
)
event["response"]["smsMessage"] = (
f"確認コードは {code} です。"
)
return event
LambdaからemailMessageやemailSubjectを変更する場合は、ユーザープールのメール送信設定でAmazon SESを使用する設定が必要です。
また、emailMessageには、event["request"]["codeParameter"]で受け取った確認コードのプレースホルダーを必ず含めます。
まとめ
Lambdaトリガーは、Cognitoの標準機能だけでは実現できない認証・ユーザー管理の要件に対応できる便利な仕組みです。
本記事で紹介した主なLambdaトリガーと役割は、次のとおりです。
Pre sign-up
→ ユーザー登録前のチェックや自動確認
Post confirmation
→ ユーザー登録確認後やパスワード再設定確認後の処理
Pre authentication
→ ログイン前の利用可否チェック
Post authentication
→ ログイン成功後のログ記録や後続処理
Pre token generation
→ IDトークンやアクセストークンのカスタマイズ
Custom message
→ Cognitoが送信するメールやSMSのカスタマイズ
一方で、認証フローの途中でLambdaを実行するため、処理時間、エラー発生時の影響、イベントバージョン、ユーザープールの機能プランなどを考慮して設計する必要があります。
まずはCognitoの処理の流れを理解し、 どのタイミングで、何を確認・変更したいのか を整理したうえで、目的に合ったLambdaトリガーを選択することが重要です。
本記事が、Amazon CognitoのLambdaトリガーを理解するきっかけや、実際のシステムで活用する際の参考になれば幸いです。
今後は、カスタム認証やユーザー移行などの応用的なLambdaトリガーについても整理していきたいと思います。
最後までお読みいただき、ありがとうございました!
