

# Customizing user pool workflows with Lambda triggers
<a name="cognito-user-pools-working-with-lambda-triggers"></a>

Amazon Cognito works with AWS Lambda functions to modify the authentication behavior of your user pool. You can configure your user pool to automatically invoke Lambda functions before their first sign-up, after they complete authentication, and at several stages in between. Your functions can modify the default behavior of your authentication flow, make API requests to modify your user pool or other AWS resources, and communicate with external systems. The code in your Lambda functions is your own. Amazon Cognito sends event data to your function, waits for the function to process the data, and in most cases anticipates a response event that reflects any changes you want to make to the session.

Within the system of request and response events, you can introduce your own authentication challenges, migrate users between your user pool and another identity store, customize messages, and modify JSON web tokens (JWTs).

Lambda triggers can customize the response that Amazon Cognito delivers to your user after they initiate an action in your user pool. For example, you can prevent sign-in by a user who would otherwise succeed. They can also perform runtime operations against your AWS environment, external APIs, databases, or identity stores. The migrate user trigger, for example, can combine external action with a change in Amazon Cognito: you can look up user information in an external directory, then set attributes on a new user based on that external information.

When you have a Lambda trigger assigned to your user pool, Amazon Cognito interrupts its default flow to request information from your function. Amazon Cognito generates a JSON *event* and passes it to your function. The event contains information about your user's request to create a user account, sign in, reset a password, or update an attribute. Your function then has an opportunity to take action, or to send the event back unmodified. An event returned unmodified notifies your user pool to proceed with the default action for the event. For example, your pre sign-up trigger can automatically confirm users for the `PreSignUp_SignUp` trigger source, but return the event unchanged for external and administrator-created users.

The following table summarizes some of the ways you can use Lambda triggers to customize user pool operations:


****  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html)

**Topics**
+ [Things to know about Lambda triggers](#important-lambda-considerations)
+ [Add a user pool Lambda trigger](#triggers-working-with-lambda)
+ [User pool Lambda trigger event](#cognito-user-pools-lambda-trigger-event-parameter-shared)
+ [User pool Lambda trigger common parameters](#cognito-user-pools-lambda-trigger-syntax-shared)
+ [Client metadata](#working-with-lambda-trigger-client-metadata)
+ [Connecting API operations to Lambda triggers](#lambda-triggers-by-event)
+ [Connecting Lambda triggers to user pool functional operations](#working-with-lambda-trigger-sources)
+ [Pre sign-up Lambda trigger](user-pool-lambda-pre-sign-up.md)
+ [Post confirmation Lambda trigger](user-pool-lambda-post-confirmation.md)
+ [Pre authentication Lambda trigger](user-pool-lambda-pre-authentication.md)
+ [Post authentication Lambda trigger](user-pool-lambda-post-authentication.md)
+ [Inbound federation Lambda trigger](user-pool-lambda-inbound-federation.md)
+ [Custom authentication challenge Lambda triggers](user-pool-lambda-challenge.md)
+ [Pre token generation Lambda trigger](user-pool-lambda-pre-token-generation.md)
+ [Migrate user Lambda trigger](user-pool-lambda-migrate-user.md)
+ [Custom message Lambda trigger](user-pool-lambda-custom-message.md)
+ [Custom sender Lambda triggers](user-pool-lambda-custom-sender-triggers.md)

## Things to know about Lambda triggers
<a name="important-lambda-considerations"></a>

When you are preparing your user pools for Lambda functions, consider the following:
+ The events that Amazon Cognito sends to your Lambda triggers might change with new features. The positions of response and request elements in the JSON hierarchy might change, or element names might be added. In your Lambda function, you can expect to receive the input-element key-value pairs described in this guide, but stricter input validation can cause your functions to fail.
+ You can choose one of multiple versions of the events that Amazon Cognito sends to some triggers. Some versions might require you to accept a change to your Amazon Cognito pricing. For more information about pricing, see [Amazon Cognito Pricing](https://aws.amazon.com/cognito/pricing/). To customize access tokens in a [Pre token generation Lambda trigger](user-pool-lambda-pre-token-generation.md), you must configure your user pool with a feature plan other than *Lite* and update your Lambda trigger configuration to use event version 2.
+ Except for [Custom sender Lambda triggers](user-pool-lambda-custom-sender-triggers.md), Amazon Cognito invokes Lambda functions synchronously. When Amazon Cognito calls your Lambda function, it must respond within 5 seconds. If it doesn't and if the call can be retried, Amazon Cognito may retry the call. If all retry attempts fail, the function times out. You can't change this five-second timeout value. For more information, see [Lambda programming model](https://docs.aws.amazon.com/lambda/latest/dg/foundation-progmodel.html) in the AWS Lambda Developer Guide.

  Amazon Cognito doesn't retry function calls that return an [Invoke error](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_Errors) with an HTTP status code of 500-599. These codes indicate a configuration issue that leaves Lambda unable to launch the function. For more information, see [Error handling and automatic retries in AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-retries.html).
+ You can't declare a function version in your Lambda trigger configuration. Amazon Cognito user pools invoke the latest version of your function by default. However, you can associate a function version with an alias and set your trigger `LambdaArn` to the alias ARN in a [CreateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html) or [UpdateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html) API request. This option isn't available in the AWS Management Console. For more information about aliases, see [Lambda function aliases](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html) in the *AWS Lambda Developer Guide*.
+ If you delete a Lambda trigger, you must update the corresponding trigger in the user pool. For example, if you delete the post authentication trigger, you must set the **Post authentication** trigger in the corresponding user pool to **none**. 
+ If your Lambda function doesn't return the request and response parameters to Amazon Cognito, or returns an error, the authentication event doesn't succeed. You can return an error in your function to prevent a user's sign-up, authentication, token generation, or any other stage of their authentication flow that invokes Lambda trigger.

  Managed login returns errors that Lambda triggers generate as error text above the sign-in prompt. The Amazon Cognito user pools API returns trigger errors in the format `[trigger] failed with error [error text from response]`. As a best practice, only generate errors in your Lambda functions that you want your users to see. Use output methods like `print()` to log any sensitive or debugging information to CloudWatch Logs. For an example, see [Pre sign-up example: Deny sign-up if user name has fewer than five characters](user-pool-lambda-pre-sign-up.md#aws-lambda-triggers-pre-registration-example-3).
+ You can add a Lambda function in another AWS account as a trigger for your user pool. You must add cross-account triggers with the [CreateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html) and [UpdateUserPool](https://docs.aws.amazon.com/) API operations, or their equivalents in CloudFormation and the AWS CLI. You can't add cross-account functions in the AWS Management Console.
+ When you add a Lambda trigger in the Amazon Cognito console, Amazon Cognito adds a resource-based policy to your function that permits your user pool to invoke the function. When you create a Lambda trigger outside of the Amazon Cognito console, including a cross-account function, you must add permissions to the resource-based policy of the Lambda function. Your added permissions must allow Amazon Cognito to invoke the function on behalf of your user pool. You can [add permissions from the Lambda Console](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html) or use the Lambda [AddPermission](https://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html) API operation.

**Example Lambda Resource-Based Policy**  
The following example Lambda resource-based policy grants Amazon Cognito a limited ability to invoke a Lambda function. Amazon Cognito can only invoke the function when it does so on behalf of both the user pool in the `aws:SourceArn` condition and the account in the `aws:SourceAccount` condition.

------
#### [ JSON ]

****  

  ```
  {
      "Version":"2012-10-17",		 	 	 
      "Id": "default",
      "Statement": [
          {
              "Sid": "LambdaCognitoIdpTrust",
              "Effect": "Allow",
              "Principal": {
                  "Service": "cognito-idp.amazonaws.com"
              },
              "Action": "lambda:InvokeFunction",
              "Resource": "arn:aws:lambda:us-east-1:111122223333:function:MyFunction",
              "Condition": {
                  "StringEquals": {
                      "AWS:SourceAccount": "111122223333"
                  },
                  "ArnLike": {
                      "AWS:SourceArn": "arn:aws:cognito-idp:us-east-1:111122223333:userpool/us-east-1_EXAMPLE"
                  }
              }
          }
      ]
  }
  ```

------

## Add a user pool Lambda trigger
<a name="triggers-working-with-lambda"></a>

**To add a user pool Lambda trigger with the console**

1. Use the [Lambda console](https://console.aws.amazon.com/lambda/home) to create a Lambda function. For more information on Lambda functions, see the [AWS Lambda Developer Guide](https://docs.aws.amazon.com/lambda/latest/dg/).

1. Go to the [Amazon Cognito console](https://console.aws.amazon.com/cognito/home), and then choose **User Pools**.

1. Choose an existing user pool from the list, or [create a user pool](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-as-user-directory.html).

1. Choose the **Extensions** menu and locate **Lambda triggers**.

1. Choose **Add a Lambda trigger**.

1. Select a Lambda trigger **Category** based on the stage of authentication that you want to customize.

1. Select **Assign Lambda function** and select a function in the same AWS Region as your user pool.
**Note**  
If your AWS Identity and Access Management (IAM) credentials have permission to update the Lambda function, Amazon Cognito adds a Lambda resource-based policy. With this policy, Amazon Cognito can invoke the function that you select. If the signed-in credentials do not have sufficient IAM permissions, you must update the resource-based policy separately. For more information, see [Things to know about Lambda triggers](#important-lambda-considerations).

1. Choose **Save changes**.

1. You can use CloudWatch in the Lambda console to log your Lambda function . For more information, see [Accessing CloudWatch Logs for Lambda](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-functions-logs.html).

## User pool Lambda trigger event
<a name="cognito-user-pools-lambda-trigger-event-parameter-shared"></a>

Amazon Cognito passes event information to your Lambda function. The Lambda function returns the same event object back to Amazon Cognito with any changes in the response. If your function returns the input event without modification, Amazon Cognito proceed with default behavior. The following shows the parameters that are common to all Lambda trigger input events. For trigger-specific event syntax, review the event schema on the section of this guide for each trigger.

------
#### [ JSON ]

```
{
    "version": "string",
    "triggerSource": "string",
    "region": AWSRegion,
    "userPoolId": "string",
    "userName": "string",
    "callerContext": 
        {
            "awsSdkVersion": "string",
            "clientId": "string"
        },
    "request":
        {
            "userAttributes": {
                "string": "string",
                ....
            }
        },
    "response": {}
}
```

------

## User pool Lambda trigger common parameters
<a name="cognito-user-pools-lambda-trigger-syntax-shared"></a>

**version**  
The version number of your Lambda function.

**triggerSource**  
The name of the event that triggered the Lambda function. For a description of each triggerSource see [Connecting Lambda triggers to user pool functional operations](#working-with-lambda-trigger-sources).

**region**  
The AWS Region as an `AWSRegion` instance.

**userPoolId**  
The ID of the user pool.

**userName**  
The current user's username.

**callerContext**  
Metadata about the request and the code environment. It contains the fields **awsSdkVersion** and **clientId**.    
**awsSdkVersion**  
The version of the AWS SDK that generated the request.  
****clientId****  
The ID of the user pool app client.

**request**  
Details of your user's API request. It includes the following fields, and any request parameters that are particular to the trigger. For example, an event that Amazon Cognito sends to a pre-authentication trigger will also contain a `userNotFound` parameter. You can process the value of this parameter to take a custom action when your user tries to sign in with an unregistered username.    
**userAttributes**  
One or more key-value pairs of user attribute names and values, for example `"email": "john@example.com"`.

**response**  
This parameter doesn't contain any information in the original request. Your Lambda function must return the entire event to Amazon Cognito, and add any return parameters to the `response`. To see what return parameters your function can include, refer to the documentation for the trigger that you want to use.

## Client metadata
<a name="working-with-lambda-trigger-client-metadata"></a>

You can submit custom parameters to your Lambda trigger functions in API operations and [Token endpoint](token-endpoint.md) requests. With client metadata, your application can collect additional information about the environment where requests originate. When you pass client metadata to your Lambda functions, they can process the additional data and make use of it in logging or customization of authentication flows. Client metadata is string pairs of your choosing and design in a JSON key-value format.

**Client metadata example use cases**
+ Pass geolocation data at sign-up to the [pre sign-up trigger](user-pool-lambda-pre-sign-up.md) and prevent sign-in from unwanted locations.
+ Pass tenant ID data to [custom challenge triggers](user-pool-lambda-challenge.md) and issue different challenges to customers from different business units.
+ Pass a user's token to the [pre token generation trigger](user-pool-lambda-pre-token-generation.md) and generate a log of the principal that an M2M request was made on behalf of. For an example request, see [Client credentials with basic authorizationClient credentials with POST body authorization](token-endpoint.md#exchanging-client-credentials-for-an-access-token-in-request-body).

Here is an example of passing client metadata to the pre sign-up trigger.

------
#### [ SignUp request ]

The following is an example [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html#CognitoUserPools-SignUp-request-ValidationData) request with client metadata that Amazon Cognito passes to a pre sign-up trigger.

```
POST HTTP/1.1
Host: cognito-idp.us-east-1.amazonaws.com
X-Amz-Date: 20230613T200059Z
Accept-Encoding: gzip, deflate, br
X-Amz-Target: AWSCognitoIdentityProviderService.SignUp
User-Agent: <UserAgentString>
Authorization: AWS4-HMAC-SHA256 Credential=<Credential>, SignedHeaders=<Headers>, Signature=<Signature>
Content-Length: <PayloadSizeBytes>

{
    "ClientId": "1example23456789",
    "Username": "mary_major",
    "Password": "<Password>",
    "SecretHash": "<Secret hash>",
    "ClientMetadata": { 
        "IpAddress" : "192.0.2.252",
        "GeoLocation" : "Netherlands (Kingdom of the) [NL]"
    }
    "UserAttributes": [
        {
            "Name": "name",
            "Value": "Mary"
        },
        {
            "Name": "email",
            "Value": "mary_major@example.com"
        },
        {
            "Name": "phone_number",
            "Value": "+12065551212"
        }
    ],
}
```

------
#### [ Lambda trigger input event ]

The request results in the following request body to your pre sign-up function.

```
{
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "1example23456789"
    },
    "region": "us-west-2",
    "request": {
        "clientMetadata": {
            "GeoLocation": "Netherlands (Kingdom of the) [NL]",
            "IpAddress": "192.0.2.252"
        },
        "userAttributes": {
            "email": "mary_major@example.com",
            "name": "Mary",
            "phone_number": "+12065551212"
        },
        "validationData": null
    },
    "response": {
        "autoConfirmUser": false,
        "autoVerifyEmail": false,
        "autoVerifyPhone": false
    },
    "triggerSource": "PreSignUp_SignUp",
    "userName": "mary_major2",
    "userPoolId": "us-west-2_EXAMPLE",
    "version": "1"
}
```

------

**Client metadata for machine-to-machine (M2M) client credentials**  
You can pass [client metadata](#working-with-lambda-trigger-client-metadata) in M2M requests. Client metadata is additional information from a user or application environment that can contribute to the outcomes of a [Pre token generation Lambda trigger](user-pool-lambda-pre-token-generation.md). In authentication operations with a user principal, you can pass client metadata to the pre token generation trigger in the body of [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API requests. Because applications conduct the flow for generation of access tokens for M2M with direct requests to the [Token endpoint](token-endpoint.md), they have a different model. In the POST body of token requests for client credentials, pass an `aws_client_metadata` parameter with the client metadata object URL-encoded (`x-www-form-urlencoded`) to string. For an example request, see [Client credentials with basic authorizationClient credentials with POST body authorization](token-endpoint.md#exchanging-client-credentials-for-an-access-token-in-request-body). The following is an example parameter that passes the key-value pairs `{"environment": "dev", "language": "en-US"}`.

```
aws_client_metadata=%7B%22environment%22%3A%20%22dev%22,%20%22language%22%3A%20%22en-US%22%7D
```

**Temporary user attributes: `validationData`**  
Some authentication operations also have a `validationData` parameter. Like client metadata, this is an opportunity to pass external information that Amazon Cognito doesn't automatically gather to Lambda triggers. The validation data field is intended to provide your Lambda function witth additional user context in sign-up and sign-in operations. [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html#CognitoUserPools-SignUp-request-ValidationData) and [AdminCreateUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html#CognitoUserPools-AdminCreateUser-request-ValidationData) pass `validationData` to the [pre sign-up trigger](user-pool-lambda-pre-sign-up.md). [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html#CognitoUserPools-InitiateAuth-request-ClientMetadata) and [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html#CognitoUserPools-AdminInitiateAuth-request-ClientMetadata) pass `ClientMetadata` in the API request body as `validationData` in the input event to the [pre authentication](user-pool-lambda-pre-authentication.md) and [migrate user](user-pool-lambda-migrate-user.md) triggers.

To map API operations to the functions that they can pass client metadata to, refer to the trigger source sections that follow.

## Connecting API operations to Lambda triggers
<a name="lambda-triggers-by-event"></a>

The following sections describe the Lambda triggers that Amazon Cognito invokes from the activity in your user pool.

When your app signs in users through the Amazon Cognito user pools API, managed login, or user pool endpoints, Amazon Cognito invokes your Lambda functions based on the session context. For more information about the Amazon Cognito user pools API and user pool endpoints, see [Understanding API, OIDC, and managed login pages authentication](authentication-flows-public-server-side.md#user-pools-API-operations). The tables in the sections that follow describe events that cause Amazon Cognito to invoke a function, and the `triggerSource` string that Amazon Cognito includes in the request.

**Topics**
+ [Lambda triggers in the Amazon Cognito API](#lambda-triggers-native-users-native-api)
+ [Lambda triggers for Amazon Cognito local users in managed login](#lambda-triggers-native-users-hosted-UI)
+ [Lambda triggers for federated users](#lambda-triggers-for-federated-users)

### Lambda triggers in the Amazon Cognito API
<a name="lambda-triggers-native-users-native-api"></a>

The following table describes the source strings for the Lambda triggers that Amazon Cognito can invoke when your app creates, signs in, or updates a local user.


**Local user trigger sources in the Amazon Cognito API**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html)

### Lambda triggers for Amazon Cognito local users in managed login
<a name="lambda-triggers-native-users-hosted-UI"></a>

The following table describes the source strings for the Lambda triggers that Amazon Cognito can invoke when a local user signs in to your user pool with managed login.


**Local user trigger sources in managed login**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html)

### Lambda triggers for federated users
<a name="lambda-triggers-for-federated-users"></a>

You can use the following Lambda triggers to customize your user pool workflows for users who sign in with a federated provider. 

**Note**  
Federated users can use managed login to sign in, or you can generate a request to the [Authorize endpoint](authorization-endpoint.md) that silently redirects them to their identity provider sign-in page. You can't sign in federated users with the Amazon Cognito user pools API.


**Federated user trigger sources**  
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html)

Federated sign-in does not invoke any [Custom authentication challenge Lambda triggers](user-pool-lambda-challenge.md), [Migrate user Lambda trigger](user-pool-lambda-migrate-user.md), [Custom message Lambda trigger](user-pool-lambda-custom-message.md), or [Custom sender Lambda triggers](user-pool-lambda-custom-sender-triggers.md) in your user pool.

## Connecting Lambda triggers to user pool functional operations
<a name="working-with-lambda-trigger-sources"></a>

Each Lambda trigger serves a functional role in your user pool. For example, a trigger can modify your sign-up flow, or add a custom authentication challenge. The event that Amazon Cognito sends to a Lambda function can reflect one of multiple actions that make up that functional role. For example, Amazon Cognito invokes a pre sign-up trigger when your user signs up, and when you create a user. Each of these different cases for the same functional role has its own `triggerSource` value. Your Lambda function can process incoming events differently based on the operation that invoked it.

Amazon Cognito also invokes all assigned functions when an event corresponds to a trigger source. For example, when a user signs in to a user pool where you assigned migrate user and pre authentication triggers, they activate both.


**Sign-up, confirmation, and sign-in (authentication) triggers**  

| Trigger | triggerSource value | Event | 
| --- | --- | --- | 
| Pre sign-up | PreSignUp\$1SignUp | Pre sign-up. | 
| Pre sign-up | PreSignUp\$1AdminCreateUser | Pre sign-up when an admin creates a new user. | 
| Pre sign-up | PreSignUp\$1ExternalProvider | Pre sign-up for external identity providers. | 
| Post confirmation | PostConfirmation\$1ConfirmSignUp | Post sign-up confirmation. | 
| Post confirmation | PostConfirmation\$1ConfirmForgotPassword | Post Forgot Password confirmation. | 
| Pre authentication | PreAuthentication\$1Authentication | Pre authentication. | 
| Post authentication | PostAuthentication\$1Authentication | Post authentication. | 


**Custom authentication challenge triggers**  

| Trigger | triggerSource value | Event | 
| --- | --- | --- | 
| Define auth challenge | DefineAuthChallenge\$1Authentication | Define Auth Challenge. | 
| Create auth challenge | CreateAuthChallenge\$1Authentication | Create Auth Challenge. | 
| Verify auth challenge | VerifyAuthChallengeResponse\$1Authentication | Verify Auth Challenge Response. | 


**Federation triggers**  

| Trigger | triggerSource value | Event | 
| --- | --- | --- | 
| Inbound federation | InboundFederation\$1ExternalProvider | Inbound federation. | 


**Pre token generation triggers**  

| Trigger | triggerSource value | Event | 
| --- | --- | --- | 
| Pre token generation | TokenGeneration\$1HostedAuth |  Amazon Cognito authenticates the user from your managed login sign-in page. | 
| Pre token generation | TokenGeneration\$1Authentication | User authentication or token refresh complete. | 
| Pre token generation | TokenGeneration\$1NewPasswordChallenge | Admin creates the user. Amazon Cognito invokes this when the user must change a temporary password. | 
| Pre token generation | TokenGeneration\$1AuthenticateDevice | End of the authentication of a user device. | 
| Pre token generation | TokenGeneration\$1RefreshTokens | User tries to refresh the identity and access tokens. | 


**Migrate user triggers**  

| Trigger | triggerSource value | Event | 
| --- | --- | --- | 
| User migration | UserMigration\$1Authentication | User migration at the time of sign-in. | 
| User migration | UserMigration\$1ForgotPassword | User migration during the forgot-password flow. | 


**Custom message triggers**  

| Trigger | triggerSource value | Event | 
| --- | --- | --- | 
| Custom message | CustomMessage\$1SignUp | Custom message when a user signs up in your user pool. | 
| Custom message | CustomMessage\$1AdminCreateUser | Custom message when you create a user as an administrator and Amazon Cognito sends them a temporary password. | 
| Custom message | CustomMessage\$1ResendCode | Custom message when your existing user requests a new confirmation code. | 
| Custom message | CustomMessage\$1ForgotPassword | Custom message when your user requests a password reset. | 
| Custom message | CustomMessage\$1UpdateUserAttribute | Custom message when a user changes their email address or phone number and Amazon Cognito sends a verification code. | 
| Custom message | CustomMessage\$1VerifyUserAttribute | Custom message when a user adds an email address or phone number and Amazon Cognito sends a verification code. | 
| Custom message | CustomMessage\$1Authentication | Custom message when a user who has configured SMS MFA signs in. | 


**Custom sender triggers**  

| Trigger | triggerSource value | Event | 
| --- | --- | --- | 
| Custom sender |  `CustomEmailSender_SignUp` `CustomSmsSender_SignUp`  | When a user signs up in your user pool. | 
| Custom sender |  `CustomEmailSender_AdminCreateUser` `CustomSmsSender_AdminCreateUser`  | When you create a user as an administrator and Amazon Cognito sends them a temporary password. | 
| Custom sender |  `CustomEmailSender_ForgotPassword` `CustomSmsSender_ForgotPassword`  | When your user requests a password reset. | 
| Custom sender |  `CustomEmailSender_UpdateUserAttribute` `CustomSmsSender_UpdateUserAttribute`  | When a user changes their email address or phone number and Amazon Cognito sends a verification code. | 
| Custom sender |  `CustomEmailSender_VerifyUserAttribute` `CustomSmsSender_VerifyUserAttribute`  | When a user adds an email address or phone number and Amazon Cognito sends a verification code. | 
| Custom sender |  `CustomEmailSender_Authentication` `CustomSmsSender_Authentication`  | When a user who has configured SMS or email MFA or OTP signs in. | 
| Custom sender | CustomEmailSender\$1AccountTakeOverNotification | When your threat protection settings take an automated action against a user's sign-in attempt and the action for the risk level includes a notification. | 

# Pre sign-up Lambda trigger
<a name="user-pool-lambda-pre-sign-up"></a>

You might want to customize the sign-up process in user pools that have self-service sign-up options. Some common uses of the pre sign-up trigger are to perform custom analysis and recording of new users, apply security and governance standards, or link users from a third-party IdP to a [consolidated user profile](cognito-user-pools-identity-federation-consolidate-users.md). You might also have trusted users who aren't required to undergo [verification and confirmation](signing-up-users-in-your-app.md).

Immediately before Amazon Cognito completes creation of a new [local](cognito-terms.md#terms-localuser) or [federated](cognito-terms.md#terms-federateduser) user, it activates the pre sign-up Lambda function. The `userAttributes` in the request object sent to this function contain attributes that have been provided by local user sign-up or that have successfully been mapped from provider attributes for a federated user. Your user pool invokes this trigger on self-service sign-up with [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html) or first sign-in with a trusted [identity provider](amazon-cognito-user-pools-authentication-flow-methods.md#amazon-cognito-user-pools-authentication-flow-methods-federated), and on user creation with [AdminCreateUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html). As part of the sign-up process, you can use this function to analyze the sign-in event with custom logic, and modify or deny the new user.

**Topics**
+ [Pre sign-up Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-pre-signup)
+ [Pre sign-up example: Auto-confirm users from a registered domain](#aws-lambda-triggers-pre-registration-example)
+ [Pre sign-up example: Auto-confirm and auto-verify all users](#aws-lambda-triggers-pre-registration-example-2)
+ [Pre sign-up example: Deny sign-up if user name has fewer than five characters](#aws-lambda-triggers-pre-registration-example-3)

## Pre sign-up Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-signup"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
            . . .
        },
        "validationData": {
            "string": "string",
            . . .
         },
        "clientMetadata": {
            "string": "string",
            . . .
         }
    },

    "response": {
        "autoConfirmUser": "boolean",
        "autoVerifyPhone": "boolean",
        "autoVerifyEmail": "boolean"
    }
}
```

------

### Pre sign-up request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-signup-request"></a>

**userAttributes**  
One or more name-value pairs representing user attributes. The attribute names are the keys.

**validationData**  
One or more key-value pairs with user attribute data that your app passed to Amazon Cognito in the request to create a new user. Send this information to your Lambda function in the ValidationData parameter of your [AdminCreateUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html) or [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html) API request.  
Amazon Cognito doesn't set your ValidationData data as attributes of the user that you create. ValidationData is temporary user information that you supply for the purposes of your pre sign-up Lambda trigger.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the Lambda function that you specify for the pre sign-up trigger. You can pass this data to your Lambda function by using the ClientMetadata parameter in the following API actions: [AdminCreateUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html), [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html), [ForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html), and [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html).

### Pre sign-up response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-signup-response"></a>

In the response, you can set `autoConfirmUser` to `true` if you want to auto-confirm the user. You can set `autoVerifyEmail` to `true` to auto-verify the user's email. You can set `autoVerifyPhone` to `true` to auto-verify the user's phone number.

**Note**  
Response parameters `autoVerifyPhone`, `autoVerifyEmail` and `autoConfirmUser` are ignored by Amazon Cognito when the pre sign-up Lambda function is triggered by the `AdminCreateUser` API.

**autoConfirmUser**  
Set to `true` to auto-confirm the user, or `false` otherwise.

**autoVerifyEmail**  
Set to `true` to set as verified the email address of a user who is signing up, or `false` otherwise. If `autoVerifyEmail` is set to `true`, the `email` attribute must have a valid, non-null value. Otherwise an error will occur and the user will not be able to complete sign-up.  
If the `email` attribute is selected as an alias, an alias will be created for the user's email address when `autoVerifyEmail` is set. If an alias with that email address already exists, the alias will be moved to the new user and the previous user's email address will be marked as unverified. For more information, see [Customizing sign-in attributes](user-pool-settings-attributes.md#user-pool-settings-aliases).

**autoVerifyPhone**  
Set to `true` to set as verified the phone number of a user who is signing up, or `false` otherwise. If `autoVerifyPhone` is set to `true`, the `phone_number` attribute must have a valid, non-null value. Otherwise an error will occur and the user will not be able to complete sign-up.  
If the `phone_number` attribute is selected as an alias, an alias will be created for the user's phone number when `autoVerifyPhone` is set. If an alias with that phone number already exists, the alias will be moved to the new user and the previous user's phone number will be marked as unverified. For more information, see [Customizing sign-in attributes](user-pool-settings-attributes.md#user-pool-settings-aliases).

## Pre sign-up example: Auto-confirm users from a registered domain
<a name="aws-lambda-triggers-pre-registration-example"></a>

This is example Lambda trigger code. The pre sign-up trigger is invoked immediately before Amazon Cognito processes the sign-up request. It uses a custom attribute **custom:domain** to automatically confirm new users from a particular email domain. Any new users not in the custom domain will be added to the user pool, but not automatically confirmed.

------
#### [ Node.js ]

```
export const handler = async (event, context, callback) => {
  // Set the user pool autoConfirmUser flag after validating the email domain
  event.response.autoConfirmUser = false;

  // Split the email address so we can compare domains
  var address = event.request.userAttributes.email.split("@");

  // This example uses a custom attribute "custom:domain"
  if (event.request.userAttributes.hasOwnProperty("custom:domain")) {
    if (event.request.userAttributes["custom:domain"] === address[1]) {
      event.response.autoConfirmUser = true;
    }
  }

  // Return to Amazon Cognito
  callback(null, event);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    # It sets the user pool autoConfirmUser flag after validating the email domain
    event['response']['autoConfirmUser'] = False

    # Split the email address so we can compare domains
    address = event['request']['userAttributes']['email'].split('@')

    # This example uses a custom attribute 'custom:domain'
    if 'custom:domain' in event['request']['userAttributes']:
        if event['request']['userAttributes']['custom:domain'] == address[1]:
            event['response']['autoConfirmUser'] = True

    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "email": "testuser@example.com",
            "custom:domain": "example.com"
        }
    },
    "response": {}
}
```

------

## Pre sign-up example: Auto-confirm and auto-verify all users
<a name="aws-lambda-triggers-pre-registration-example-2"></a>

This example confirms all users and sets the user's `email` and `phone_number` attributes to verified if the attribute is present. Also, if aliasing is enabled, aliases will be created for `phone_number` and `email` when auto-verify is set. 

**Note**  
If an alias with the same phone number already exists, the alias will be moved to the new user, and the previous user's `phone_number` will be marked as unverified. The same is true for email addresses. To prevent this from happening, you can use the user pools [ListUsers API](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListUsers.html) to see if there is an existing user who is already using the new user's phone number or email address as an alias.

------
#### [ Node.js ]

```
exports.handler = (event, context, callback) => {
  // Confirm the user
  event.response.autoConfirmUser = true;

  // Set the email as verified if it is in the request
  if (event.request.userAttributes.hasOwnProperty("email")) {
    event.response.autoVerifyEmail = true;
  }

  // Set the phone number as verified if it is in the request
  if (event.request.userAttributes.hasOwnProperty("phone_number")) {
    event.response.autoVerifyPhone = true;
  }

  // Return to Amazon Cognito
  callback(null, event);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    # Confirm the user
    event['response']['autoConfirmUser'] = True

    # Set the email as verified if it is in the request
    if 'email' in event['request']['userAttributes']:
        event['response']['autoVerifyEmail'] = True

    # Set the phone number as verified if it is in the request
    if 'phone_number' in event['request']['userAttributes']:
        event['response']['autoVerifyPhone'] = True

    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
  "request": {
    "userAttributes": {
      "email": "user@example.com",
      "phone_number": "+12065550100"
    }
  },
  "response": {}
}
```

------

## Pre sign-up example: Deny sign-up if user name has fewer than five characters
<a name="aws-lambda-triggers-pre-registration-example-3"></a>

This example checks the length of the user name in a sign-up request. The example returns an error if the user has entered a name less than five characters long.

------
#### [ Node.js ]

```
export const handler = (event, context, callback) => {
    // Impose a condition that the minimum length of the username is 5 is imposed on all user pools.
    if (event.userName.length < 5) {
        var error = new Error("Cannot register users with username less than the minimum length of 5");
        // Return error to Amazon Cognito
        callback(error, event);
    }
    // Return to Amazon Cognito
    callback(null, event);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    if len(event['userName']) < 5:
        raise Exception("Cannot register users with username less than the minimum length of 5")
    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
  "userName": "rroe",
  "response": {}
}
```

------

# Post confirmation Lambda trigger
<a name="user-pool-lambda-post-confirmation"></a>

Amazon Cognito invokes this trigger after a signed-up user confirms their user account. In your post confirmation Lambda function, you can send custom messages or add custom API requests. For example, you can query an external system and populate additional attributes to the user. Amazon Cognito invokes this trigger only for user who sign up in your user pool, not for user accounts that you create with your administrator credentials.

The request contains the current attributes for the confirmed user. Your user pool invokes your post confirmation function on [ConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmSignUp.html), [AdminConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminConfirmSignUp.html), and [ConfirmForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmForgotPassword.html). This trigger also runs when users confirm sign-up or password reset in [managed login](cognito-user-pools-managed-login.md).

**Topics**
+ [Post confirmation Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-post-confirmation)
+ [Post confirmation example](#aws-lambda-triggers-post-confirmation-example)

## Post confirmation Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-post-confirmation"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
            "userAttributes": {
                "string": "string",
                . . .
            },
            "clientMetadata": {
            	"string": "string",
            	. . .
            }
        },
    "response": {}
}
```

------

### Post confirmation request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-post-confirmation-request"></a>

**userAttributes**  
One or more key-value pairs representing user attributes.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the Lambda function that you specify for the post confirmation trigger. You can pass this data to your Lambda function by using the ClientMetadata parameter in the following API actions: [AdminConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminConfirmSignUp.html), [ConfirmForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmForgotPassword.html), [ConfirmSignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ConfirmSignUp.html), and [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html).

### Post confirmation response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-post-confirmation-response"></a>

No additional return information is expected in the response.

## Post confirmation example
<a name="aws-lambda-triggers-post-confirmation-example"></a>

This example Lambda function sends a confirmation email message to your user using Amazon SES. For more information see [Amazon Simple Email Service Developer Guide](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/). 

------
#### [ Node.js ]

```
// Import required AWS SDK clients and commands for Node.js. Note that this requires
// the `@aws-sdk/client-ses` module to be either bundled with this code or included
// as a Lambda layer.
import { SES, SendEmailCommand } from "@aws-sdk/client-ses";
const ses = new SES();

const handler = async (event) => {
  if (event.request.userAttributes.email) {
    await sendTheEmail(
      event.request.userAttributes.email,
      `Congratulations ${event.userName}, you have been confirmed.`,
    );
  }
  return event;
};

const sendTheEmail = async (to, body) => {
  const eParams = {
    Destination: {
      ToAddresses: [to],
    },
    Message: {
      Body: {
        Text: {
          Data: body,
        },
      },
      Subject: {
        Data: "Cognito Identity Provider registration completed",
      },
    },
    // Replace source_email with your SES validated email address
    Source: "<source_email>",
  };
  try {
    await ses.send(new SendEmailCommand(eParams));
  } catch (err) {
    console.log(err);
  }
};

export { handler };
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "email": "user@example.com",
            "email_verified": true
        }
    },
    "response": {}
}
```

------

# Pre authentication Lambda trigger
<a name="user-pool-lambda-pre-authentication"></a>

Amazon Cognito invokes this trigger when a user attempts to sign in so that you can create custom validation that performs preparatory actions. For example, you can deny the authentication request or record session data to an external system.

**Note**  
This Lambda trigger doesn't activate when a user doesn't exist unless the `PreventUserExistenceErrors` setting of a user pool app client is set to `ENABLED`. Renewal of an existing authentication session also doesn't activate this trigger.

**Topics**
+ [Flow overview](#user-pool-lambda-pre-authentication-1)
+ [Pre authentication Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-pre-auth)
+ [Pre authentication example](#aws-lambda-triggers-pre-authentication-example)

## Flow overview
<a name="user-pool-lambda-pre-authentication-1"></a>

![\[Pre authentication Lambda trigger - client flow\]](http://docs.aws.amazon.com/cognito/latest/developerguide/images/lambda-pre-authentication-1.png)


The request includes client validation data from the `ClientMetadata` values that your app passes to the user pool `InitiateAuth` and `AdminInitiateAuth` API operations.

For more information, see [An example authentication session](authentication.md#amazon-cognito-user-pools-authentication-flow).

## Pre authentication Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-auth"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
            . . .
        },
        "validationData": {
            "string": "string",
            . . .
        },
        "userNotFound": boolean
    },
    "response": {}
}
```

------

### Pre authentication request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-auth-request"></a>

**userAttributes**  
One or more name-value pairs that represent user attributes.

**userNotFound**  
When you set `PreventUserExistenceErrors` to `ENABLED` for your user pool client, Amazon Cognito populates this Boolean.

**validationData**  
One or more key-value pairs that contain the validation data in the user's sign-in request. To pass this data to your Lambda function, use the ClientMetadata parameter in the [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) and [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) API actions.

### Pre authentication response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-auth-response"></a>

Amazon Cognito doesn't process any added information that your function returns in the response. Your function can return an error to reject the sign-in attempt, or use API operations to query and modify your resources.

## Pre authentication example
<a name="aws-lambda-triggers-pre-authentication-example"></a>

This example function prevents users from signing in to your user pool with a specific app client. Because the pre authentication Lambda function doesn't invoke when your user has an existing session, this function only prevents *new* sessions with the app client ID that you want to block.

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (
    event.callerContext.clientId === "user-pool-app-client-id-to-be-blocked"
  ) {
    throw new Error("Cannot authenticate users from this user pool app client");
  }

  return event;
};

export { handler };
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    if event['callerContext']['clientId'] == "<user pool app client id to be blocked>":
        raise Exception("Cannot authenticate users from this user pool app client")

    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample: 

------
#### [ JSON ]

```
{
    "callerContext": {
        "clientId": "<user pool app client id to be blocked>"
    },
    "response": {}
}
```

------

# Post authentication Lambda trigger
<a name="user-pool-lambda-post-authentication"></a>

The post authentication trigger doesn't change the authentication flow for a user. Amazon Cognito invokes this Lambda after authentication is complete, before a user has received tokens. Add a post authentication trigger when you want to add custom post-processing of authentication events, for example logging or user profile adjustments that will be reflected on the next sign-in.

A post authentication Lambda that doesn't return the request body to Amazon Cognito can still cause authentication to fail to complete. For more information, see [Things to know about Lambda triggers](cognito-user-pools-working-with-lambda-triggers.md#important-lambda-considerations).

**Topics**
+ [Authentication flow overview](#user-pool-lambda-post-authentication-1)
+ [Post authentication Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-post-auth)
+ [Post authentication example](#aws-lambda-triggers-post-authentication-example)

## Authentication flow overview
<a name="user-pool-lambda-post-authentication-1"></a>

![\[Post authentication Lambda trigger - client flow\]](http://docs.aws.amazon.com/cognito/latest/developerguide/images/lambda-post-authentication-1.png)


For more information, see [An example authentication session](authentication.md#amazon-cognito-user-pools-authentication-flow).

## Post authentication Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-post-auth"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
             "string": "string",
             . . .
         },
         "newDeviceUsed": boolean,
         "clientMetadata": {
             "string": "string",
             . . .
            }
        },
    "response": {}
}
```

------

### Post authentication request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-post-auth-request"></a>

**newDeviceUsed**  
This flag indicates if the user has signed in on a new device. Amazon Cognito only sets this flag if the remembered devices value of the user pool is `Always` or `User Opt-In`.

**userAttributes**  
One or more name-value pairs representing user attributes.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the Lambda function that you specify for the post authentication trigger. To pass this data to your Lambda function, you can use the ClientMetadata parameter in the [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API actions. Amazon Cognito doesn't include data from the ClientMetadata parameter in [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) and [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) API operations in the request that it passes to the post authentication function.

### Post authentication response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-post-auth-response"></a>

Amazon Cognito doesn't expect any additional return information in the response. Your function can use API operations to query and modify your resources, or record event metadata to an external system.

## Post authentication example
<a name="aws-lambda-triggers-post-authentication-example"></a>

This post authentication sample Lambda function sends data from a successful sign-in to CloudWatch Logs.

------
#### [ Node.js ]

```
const handler = async (event) => {
  // Send post authentication data to Amazon CloudWatch logs
  console.log("Authentication successful");
  console.log("Trigger function =", event.triggerSource);
  console.log("User pool = ", event.userPoolId);
  console.log("App client ID = ", event.callerContext.clientId);
  console.log("User ID = ", event.userName);

  return event;
};

export { handler };
```

------
#### [ Python ]

```
import os
def lambda_handler(event, context):

    # Send post authentication data to Cloudwatch logs
    print ("Authentication successful")
    print ("Trigger function =", event['triggerSource'])
    print ("User pool = ", event['userPoolId'])
    print ("App client ID = ", event['callerContext']['clientId'])
    print ("User ID = ", event['userName'])

    # Return to Amazon Cognito
    return event
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
  "triggerSource": "testTrigger",
  "userPoolId": "testPool",
  "userName": "testName",
  "callerContext": {
      "clientId": "12345"
  },
  "response": {}
}
```

------

# Inbound federation Lambda trigger
<a name="user-pool-lambda-inbound-federation"></a>

The inbound federation trigger transforms federated user attributes during the authentication process with external identity providers. When users authenticate through configured identity providers, this trigger allows you to modify responses from external SAML and OIDC providers by intercepting and transforming data in the authentication process, providing programmatic control over how Amazon Cognito user pools handle federated users and their attributes.

Use this trigger to add, override, or suppress attributes before creating new users or updating existing federated user profiles. This trigger receives raw identity provider attributes as input and returns modified attributes that Amazon Cognito applies to the user profile.

**Topics**
+ [Flow overview](#cognito-user-pools-lambda-trigger-inbound-federation-flow)
+ [Inbound federation Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-inbound-federation)
+ [Inbound federation example: Group membership management](#aws-lambda-triggers-inbound-federation-example-groups)
+ [Inbound federation example: Truncate large attributes](#aws-lambda-triggers-inbound-federation-example-truncate)
+ [Inbound federation example: Logging federation events](#aws-lambda-triggers-inbound-federation-example-logging)

## Flow overview
<a name="cognito-user-pools-lambda-trigger-inbound-federation-flow"></a>

When a user authenticates with an external identity provider, Amazon Cognito invokes the inbound federation trigger before creating or updating the user profile. The trigger receives the raw attributes from the identity provider and can transform them before Amazon Cognito stores them. This flow occurs for both new federated users and existing users who sign in again through federation.

![\[Inbound federation Lambda trigger flow\]](http://docs.aws.amazon.com/cognito/latest/developerguide/images/lambda-inbound-federation.png)


## Inbound federation Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": AWSRegion,
    "userPoolId": "string",
    "userName": "string",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "string",
        "providerType": "string",
        "attributes": {
            "tokenResponse": {
                "access_token": "string",
                "token_type": "string",
                "expires_in": "string"
            },
            "idToken": {
                "sub": "string",
                "email": "string",
                "email_verified": "string"
            },
            "userInfo": {
                "email": "string",
                "given_name": "string",
                "family_name": "string"
            },
            "samlResponse": {
                "string": "string"
            }
        }
    },
    "response": {
        "userAttributesToMap": {
            "string": "string"
        }
    }
}
```

------

### Inbound federation request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation-request"></a>

**providerName**  
The name of the external identity provider.

**providerType**  
The type of the external identity provider. Valid values: `OIDC`, `SAML`, `Facebook`, `Google`, `SignInWithApple`, `LoginWithAmazon`.

**attributes**  
The raw attributes received from the identity provider before processing. The structure varies based on provider type.

**attributes.tokenResponse**  
OAuth token response data from the `/token` endpoint. Available for OIDC and social providers only. Contains `access_token`, `id_token`, `refresh_token`, `token_type`, `expires_in`, and `scope`.

**attributes.idToken**  
Decoded and validated ID token JWT claims. Available for OIDC and social providers only. Contains verified user identity information including `sub` (unique user identifier), `email`, `name`, `iss` (issuer), `aud` (audience), `exp` (expiration), and `iat` (issued time).

**attributes.userInfo**  
Extended user profile information from the UserInfo endpoint. Available for OIDC and social providers only. Contains detailed profile attributes such as `given_name`, `family_name`, `picture`, `address`, and other provider-specific fields. May be empty if the IdP doesn't support the UserInfo endpoint or if the endpoint call fails.

**attributes.samlResponse**  
SAML assertion attributes. Available for SAML providers only. Contains attributes from the SAML response.

### Inbound federation response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-inbound-federation-response"></a>

**userAttributesToMap**  
The user attributes to apply to the user profile.

**Important**  
You must include ALL user attributes you want to retain in the response, including attributes you are not modifying. Any attributes not included in the `userAttributesToMap` response will be dropped and not stored in the user profile. This applies to both modified and unmodified attributes.

**Empty response behavior**  
If you return an empty object `{}` for `userAttributesToMap`, all original attributes from the identity provider are retained unchanged. This acts as a no-op, as if the Lambda function was never executed. This is different from omitting attributes, which drops them.

**Provider-specific attributes**  
The structure of `request.attributes` varies based on the `providerType`. OIDC and social providers include `tokenResponse`, `idToken`, and `userInfo` objects. SAML providers include only the `samlResponse` object.

## Inbound federation example: Group membership management
<a name="aws-lambda-triggers-inbound-federation-example-groups"></a>

This example shows how to map federated identity provider groups to Amazon Cognito user pools groups. This function extracts group membership from the federated response and automatically adds users to corresponding Amazon Cognito groups, eliminating the need for post-authentication triggers.

------
#### [ Node.js ]

```
exports.handler = async (event) => {
    const { providerType, attributes } = event.request;
    
    // Extract user attributes based on provider type
    let userAttributesFromIdp = {};
    if (providerType === 'SAML') {
        userAttributesFromIdp = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        userAttributesFromIdp = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    // Extract groups from federated response
    const federatedGroups = userAttributesFromIdp.groups?.split(',') || [];
    
    // Map federated groups to Cognito groups
    const groupMapping = {
        'Domain Admins': 'Administrators',
        'Engineering': 'Developers',
        'Sales': 'SalesTeam'
    };
    
    // Filter to only in-scope groups
    const mappedGroups = federatedGroups
        .map(group => groupMapping[group.trim()])
        .filter(group => group); // Remove undefined values
    
    // Pass through attributes with mapped groups as custom attribute
    const attributesToMap = {
        ...userAttributesFromIdp,
        'custom:user_groups': mappedGroups.join(',')
    };
    
    // Remove original groups attribute
    delete attributesToMap.groups;
    
    event.response.userAttributesToMap = attributesToMap;
    return event;
};
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
    "userPoolId": "us-east-1_XXXXXXXXX",
    "request": {
        "providerName": "CorporateAD",
        "providerType": "SAML",
        "attributes": {
            "samlResponse": {
                "email": "jane.smith@company.com",
                "given_name": "Jane",
                "family_name": "Smith",
                "groups": "Engineering,Domain Admins",
                "department": "Engineering"
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

## Inbound federation example: Truncate large attributes
<a name="aws-lambda-triggers-inbound-federation-example-truncate"></a>

This example shows how to truncate attribute values that exceed Amazon Cognito's storage limits. This function checks each attribute from the identity provider. If an attribute value exceeds 2048 characters, it truncates the value and adds ellipsis to indicate truncation. All other attributes pass through unchanged.

------
#### [ Node.js ]

```
exports.handler = async (event) => {
    const MAX_ATTRIBUTE_LENGTH = 2048;
    
    // Get the identity provider attributes based on provider type
    const { providerType, attributes } = event.request;
    let idpAttributes = {};
    
    if (providerType === 'SAML') {
        idpAttributes = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        idpAttributes = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    const userAttributes = {};
    
    // Process each attribute
    for (const [key, value] of Object.entries(idpAttributes)) {
        if (typeof value === 'string' && value.length > MAX_ATTRIBUTE_LENGTH) {
            // Truncate the value and add ellipsis
            userAttributes[key] = value.substring(0, MAX_ATTRIBUTE_LENGTH - 3) + '...';
            console.log(`Truncated attribute ${key} from ${value.length} to ${userAttributes[key].length} characters`);
        } else {
            // Keep the original value
            userAttributes[key] = value;
        }
    }
    
    // Return the modified attributes
    event.response.userAttributesToMap = userAttributes;
    return event;
};
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": "us-east-1",
    "userPoolId": "us-east-1_XXXXXXXXX",
    "userName": "ExampleProvider_12345",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "ExampleProvider",
        "providerType": "OIDC",
        "attributes": {
            "tokenResponse": {
                "access_token": "abcDE...",
                "token_type": "Bearer",
                "expires_in": "3600"
            },
            "idToken": {
                "sub": "12345",
                "email": "user@example.com"
            },
            "userInfo": {
                "email": "user@example.com",
                "given_name": "Example",
                "family_name": "User",
                "bio": "This is a very long biography that contains more than 2048 characters..."
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

## Inbound federation example: Logging federation events
<a name="aws-lambda-triggers-inbound-federation-example-logging"></a>

This example shows how to log federated authentication events for monitoring and debugging. This example function captures detailed information about federated users and their attributes, providing visibility into the authentication process.

------
#### [ Node.js ]

```
exports.handler = async (event) => {
    const { providerName, providerType, attributes } = event.request;
    
    // Extract user attributes based on provider type
    let userAttributesFromIdp = {};
    if (providerType === 'SAML') {
        userAttributesFromIdp = attributes.samlResponse || {};
    } else {
        // For OIDC and Social providers, merge userInfo and idToken
        userAttributesFromIdp = {
            ...(attributes.userInfo || {}),
            ...(attributes.idToken || {})
        };
    }
    
    // Log federated authentication details
    console.log(JSON.stringify({
        timestamp: new Date().toISOString(),
        providerName,
        providerType,
        userEmail: userAttributesFromIdp.email,
        attributeCount: Object.keys(userAttributesFromIdp).length,
        attributes: userAttributesFromIdp
    }));
    
    // Pass through all attributes unchanged
    event.response.userAttributesToMap = userAttributesFromIdp;
    return event;
};
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
    "version": "string",
    "triggerSource": "InboundFederation_ExternalProvider",
    "region": "us-east-1",
    "userPoolId": "us-east-1_XXXXXXXXX",
    "userName": "CorporateAD_john.doe",
    "callerContext": {
        "awsSdkVersion": "string",
        "clientId": "string"
    },
    "request": {
        "providerName": "CorporateAD",
        "providerType": "SAML",
        "attributes": {
            "samlResponse": {
                "email": "john.doe@company.com",
                "given_name": "John",
                "family_name": "Doe",
                "department": "Engineering",
                "employee_id": "EMP12345"
            }
        }
    },
    "response": {
        "userAttributesToMap": {}
    }
}
```

------

Expected CloudWatch Logs output:

------
#### [ JSON ]

```
{
    "timestamp": "2025-01-14T21:17:40.153Z",
    "providerName": "CorporateAD",
    "providerType": "SAML",
    "userEmail": "john.doe@company.com",
    "attributeCount": 5,
    "attributes": {
        "email": "john.doe@company.com",
        "given_name": "John",
        "family_name": "Doe",
        "department": "Engineering",
        "employee_id": "EMP12345"
    }
}
```

------

# Custom authentication challenge Lambda triggers
<a name="user-pool-lambda-challenge"></a>

As you build out your authentication flows for your Amazon Cognito user pool, you might find that you want to extend your authentication model beyond the built-in flows. One common use case for the custom challenge triggers is to implement additional security checks beyond username, password, and multi-factor authentication (MFA). A custom challenge is any question and response you can generate in a Lambda-supported programming language. For example, you might want to require users to solve a CAPTCHA or answer a security question before being allowed to authenticate. Another potential need is to integrate with specialized authentication factors or devices. Or you might have already developed software that authenticates users with a hardware security key or a biometric device. The definition of authentication success for a custom challenge is whatever answer your Lambda function accepts as correct: a fixed string, for example, or a satisfactory response from an external API.

You can start authentication with your custom challenge and control the authentication process entirely, or you can perform username-password authentication before your application receives your custom challenge.

The custom authentication challenge Lambda trigger:

**[Defines](user-pool-lambda-define-auth-challenge.md)**  
Initiates a challenge sequence. Determines whether you want to initiate a new challenge, mark authentication as complete, or halt the authentication attempt.

**[Creates](user-pool-lambda-create-auth-challenge.md)**  
Issues the question to your application that the user must answer. This function might present a security question or a link to a CAPTCHA that your application should display to your user.

**[Verifies](user-pool-lambda-verify-auth-challenge-response.md)**  
Knows the expected answer and compares it to the answer your application provides in the challenge response. The function might call the API of your CAPTCHA service to retrieve the expected results of your user's attempted solution.

These three Lambda functions chain together to present an authentication mechanism that is completely within your control and of your own design. Because custom authentication requires application logic in your client and in the Lambda functions, you can't process custom authentication within managed login. This authentication system requires additional developer effort. Your application must perform the authentication flow with the user pools API and handle the resulting challenge with a custom-built login interface that renders the question at the center of the custom authentication challenge.

![\[Challenge Lambda triggers\]](http://docs.aws.amazon.com/cognito/latest/developerguide/images/lambda-challenges.png)


For more information about implementing custom authentication, see [Custom authentication flow and challenges](amazon-cognito-user-pools-authentication-flow-methods.md#Custom-authentication-flow-and-challenges)

Authentication between the API operations [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) or [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html), and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) or [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html). In this flow, a user authenticates by answering successive challenges until authentication either fails or the user is issued tokens. A challenge response might be a new challenge. In this case, your application responds as many times as necessary to new challenges. Successful authentication happens when the define auth challenge function analyzes the results so far, determines all challenges have been answered, and returns `IssueTokens`.

**Topics**
+ [SRP authentication in custom challenge flows](#user-pool-lambda-challenge-srp-authentication)
+ [Define Auth challenge Lambda trigger](user-pool-lambda-define-auth-challenge.md)
+ [Create Auth challenge Lambda trigger](user-pool-lambda-create-auth-challenge.md)
+ [Verify Auth challenge response Lambda trigger](user-pool-lambda-verify-auth-challenge-response.md)

## SRP authentication in custom challenge flows
<a name="user-pool-lambda-challenge-srp-authentication"></a>

You can have Amazon Cognito verify user passwords before it issues your custom challenges. Any Lambda triggers associated in the Authentication category of [request-rate quotas](quotas.md#category_operations.title) will run when you perform SRP authentication in a custom challenge flow. Here is an overview of the process:

1. Your app initiates sign-in by calling `InitiateAuth` or `AdminInitiateAuth` with the `AuthParameters` map. Parameters must include `CHALLENGE_NAME: SRP_A,` and values for `SRP_A` and `USERNAME`.

1. Amazon Cognito invokes your define auth challenge Lambda trigger with an initial session that contains `challengeName: SRP_A` and `challengeResult: true`.

1. After receiving those inputs, your Lambda function responds with `challengeName: PASSWORD_VERIFIER`, `issueTokens: false`, `failAuthentication: false`.

1. If the password verification succeeds, Amazon Cognito invokes your Lambda function again with a new session containing `challengeName: PASSWORD_VERIFIER` and `challengeResult: true`.

1. To initiate your custom challenges, your Lambda function responds with `challengeName: CUSTOM_CHALLENGE`, `issueTokens: false`, and `failAuthentication: false`. If you don't want to start your custom auth flow with password verification, you can initiate sign-in with the `AuthParameters` map including `CHALLENGE_NAME: CUSTOM_CHALLENGE`.

1. The challenge loop repeats until all challenges are answered.

The following is an example of a starting `InitiateAuth` request that precedes custom authentication with an SRP flow.

```
{
    "AuthFlow": "CUSTOM_AUTH",
    "ClientId": "1example23456789",
    "AuthParameters": {
        "CHALLENGE_NAME": "SRP_A",
        "USERNAME": "testuser",
        "SRP_A": "[SRP_A]",
        "SECRET_HASH": "[secret hash]"
    }
}
```

### Password reset in the custom authentication SRP flow
<a name="user-pool-lambda-challenge-force-password-change"></a>

When users are in `FORCE_CHANGE_PASSWORD` status, your custom authentication flow must integrate the password change step while maintaining the integrity of your authentication challenges. Amazon Cognito invokes your [define auth challenge](user-pool-lambda-define-auth-challenge.md) Lambda trigger during the `NEW_PASSWORD_REQUIRED` challenge. In this scenario, a user signing in with a custom challenge flow and SRP authentication can set a new password if they are in a password-reset state.

When users are in the `RESET_REQUIRED` or `FORCE_CHANGE_PASSWORD` status, they must [respond](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html#API_RespondToAuthChallenge_RequestParameters) to a `NEW_PASSWORD_REQUIRED` challenge with a `NEW_PASSWORD`. In custom authentication with SRP, Amazon Cognito returns a `NEW_PASSWORD_REQUIRED` challenge after users complete the SRP `PASSWORD_VERIFIER` challenge. Your define auth challenge trigger receives both challenge results in the `session` array, and can proceed with additional custom challenges after the user successfully changes their password.

Your define auth challenge Lambda trigger must manage the challenge sequence through SRP authentication, password reset, and subsequent custom challenges. The trigger receives an array of completed challenges in the `session` parameter, including both `PASSWORD_VERIFIER` and `NEW_PASSWORD_REQUIRED` results. For an example implementation, see [Define Auth challenge example](user-pool-lambda-define-auth-challenge.md#aws-lambda-triggers-define-auth-challenge-example).

#### Authentication flow steps
<a name="user-pool-lambda-challenge-password-flow-steps"></a>

For users who need to verify their password before custom challenges, the process follows these steps:

1. Your app initiates sign-in by calling `InitiateAuth` or `AdminInitiateAuth` with the `AuthParameters` map. Parameters must include `CHALLENGE_NAME: SRP_A`, and values for `SRP_A` and `USERNAME`.

1. Amazon Cognito invokes your define auth challenge Lambda trigger with an initial session that contains `challengeName: SRP_A` and `challengeResult: true`.

1. After receiving those inputs, your Lambda function responds with `challengeName: PASSWORD_VERIFIER`, `issueTokens: false`, `failAuthentication: false`.

1. If the password verification succeeds, one of two things happens:  
**For users in normal status:**  
Amazon Cognito invokes your Lambda function again with a new session containing `challengeName: PASSWORD_VERIFIER` and `challengeResult: true`.  
To initiate your custom challenges, your Lambda function responds with `challengeName: CUSTOM_CHALLENGE`, `issueTokens: false`, and `failAuthentication: false`.  
**For users in `RESET_REQUIRED` or `FORCE_CHANGE_PASSWORD` status:**  
Amazon Cognito invokes your Lambda function with a session containing `challengeName: PASSWORD_VERIFIER` and `challengeResult: true`.  
Your Lambda function should respond with `challengeName: NEW_PASSWORD_REQUIRED`, `issueTokens: false`, and `failAuthentication: false`.  
After successful password change, Amazon Cognito invokes your Lambda function with a session containing both the `PASSWORD_VERIFIER` and `NEW_PASSWORD_REQUIRED` results.  
To initiate your custom challenges, your Lambda function responds with `challengeName: CUSTOM_CHALLENGE`, `issueTokens: false`, and `failAuthentication: false`.

1. The challenge loop repeats until all challenges are answered.

If you don't want to start your custom auth flow with password verification, you can initiate sign-in with the `AuthParameters` map including `CHALLENGE_NAME: CUSTOM_CHALLENGE`.

#### Session management
<a name="user-pool-lambda-challenge-session-management"></a>

The authentication flow maintains session continuity through a series of session IDs and challenge results. Each challenge response generates a new session ID to prevent session reuse errors, which is particularly important for multi-factor authentication flows.

Challenge results are stored chronologically in the session array that your Lambda triggers receive. For users in `FORCE_CHANGE_PASSWORD` status, the session array contains:

1. `session[0]` - Initial `SRP_A` challenge

1. `session[1]` - `PASSWORD_VERIFIER` result

1. `session[2]` - `NEW_PASSWORD_REQUIRED` result

1. Subsequent elements - Results of additional custom challenges

#### Example authentication flow
<a name="user-pool-lambda-challenge-example-flow"></a>

The following example demonstrates a complete custom authentication flow for a user in `FORCE_CHANGE_PASSWORD` status who must complete both password change and a custom CAPTCHA challenge.

1. **InitiateAuth request**

   ```
   {
       "AuthFlow": "CUSTOM_AUTH",
       "ClientId": "1example23456789",
       "AuthParameters": {
           "CHALLENGE_NAME": "SRP_A",
           "USERNAME": "testuser",
           "SRP_A": "[SRP_A]"
       }
   }
   ```

1. **InitiateAuth response**

   ```
   {
       "ChallengeName": "PASSWORD_VERIFIER",
       "ChallengeParameters": {
           "USER_ID_FOR_SRP": "testuser"
       },
       "Session": "[session_id_1]"
   }
   ```

1. **RespondToAuthChallenge request with `PASSWORD_VERIFIER`**

   ```
   {
       "ChallengeName": "PASSWORD_VERIFIER",
       "ClientId": "1example23456789",
       "ChallengeResponses": {
           "PASSWORD_CLAIM_SIGNATURE": "[claim_signature]",
           "PASSWORD_CLAIM_SECRET_BLOCK": "[secret_block]",
           "TIMESTAMP": "[timestamp]",
           "USERNAME": "testuser"
       },
       "Session": "[session_id_1]"
   }
   ```

1. **RespondToAuthChallenge response with `NEW_PASSWORD_REQUIRED` challenge**

   ```
   {
       "ChallengeName": "NEW_PASSWORD_REQUIRED",
       "ChallengeParameters": {},
       "Session": "[session_id_2]"
   }
   ```

1. **RespondToAuthChallenge request with `NEW_PASSWORD_REQUIRED`**

   ```
   {
       "ChallengeName": "NEW_PASSWORD_REQUIRED",
       "ClientId": "1example23456789",
       "ChallengeResponses": {
           "NEW_PASSWORD": "[password]",
           "USERNAME": "testuser"
       },
       "Session": "[session_id_2]"
   }
   ```

1. **RespondToAuthChallenge response with CAPTCHA custom challenge**

   ```
   {
       "ChallengeName": "CUSTOM_CHALLENGE",
       "ChallengeParameters": {
           "captchaUrl": "url/123.jpg"
       },
       "Session": "[session_id_3]"
   }
   ```

1. **RespondToAuthChallenge request with answer to CAPTCHA custom challenge**

   ```
   {
       "ChallengeName": "CUSTOM_CHALLENGE",
       "ClientId": "1example23456789",
       "ChallengeResponses": {
           "ANSWER": "123",
           "USERNAME": "testuser"
       },
       "Session": "[session_id_3]"
   }
   ```

**6. Final success response**

```
{
    "AuthenticationResult": {
        "AccessToken": "eyJra456defEXAMPLE",
        "ExpiresIn": 3600,
        "IdToken": "eyJra789ghiEXAMPLE",
        "RefreshToken": "eyJjd123abcEXAMPLE",
        "TokenType": "Bearer"
    },
    "ChallengeParameters": {}
}
```

# Define Auth challenge Lambda trigger
<a name="user-pool-lambda-define-auth-challenge"></a>

The define auth challenge trigger is a Lambda function that maintains the challenge sequence in a custom authentication flow. It declares success or failure of the challenge sequence, and sets the next challenge if the sequence isn't yet complete.

![\[Challenge Lambda triggers\]](http://docs.aws.amazon.com/cognito/latest/developerguide/images/lambda-challenges1.png)


**Define auth challenge**  
 Amazon Cognito invokes this trigger to initiate the [custom authentication flow](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow).

The request for this Lambda trigger contains `session`. The `session` parameter is an array that contains all of the challenges that are presented to the user in the current authentication process. The request also includes the corresponding result. The `session` array stores challenge details (`ChallengeResult`) in chronological order. The challenge `session[0]` represents the first challenge that the user receives.

**Topics**
+ [Define Auth challenge Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-define-auth-challenge)
+ [Define Auth challenge example](#aws-lambda-triggers-define-auth-challenge-example)

## Define Auth challenge Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-define-auth-challenge"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
                . . .
        },
        "session": [
            ChallengeResult,
            . . .
        ],
        "clientMetadata": {
            "string": "string",
            . . .
        },
        "userNotFound": boolean
    },
    "response": {
        "challengeName": "string",
        "issueTokens": boolean,
        "failAuthentication": boolean
    }
}
```

------

### Define Auth challenge request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-define-auth-challenge-request"></a>

 When Amazon Cognito invokes your Lambda function, Amazon Cognito provides the following parameters:

**userAttributes**  
One or more name-value pairs that represent user attributes.

**userNotFound**  
A Boolean that Amazon Cognito populates when `PreventUserExistenceErrors` is set to `ENABLED` for your user pool client. A value of `true` means that the user id (username, email address, and other details) did not match any existing users. When `PreventUserExistenceErrors` is set to `ENABLED`, the service doesn't inform the app of nonexistent users. We recommend that your Lambda functions maintain the same user experience and account for latency. This way, the caller can't detect different behavior when the user exists or doesn’t exist.

**session**  
An array of `ChallengeResult` elements. Each contains the following elements:    
**challengeName**  
One of the following challenge types: `CUSTOM_CHALLENGE`, `SRP_A`, `PASSWORD_VERIFIER`, `SMS_MFA`, `EMAIL_OTP`, `SOFTWARE_TOKEN_MFA`, `DEVICE_SRP_AUTH`, `DEVICE_PASSWORD_VERIFIER`, or `ADMIN_NO_SRP_AUTH`.  
When your define auth challenge function issues a `PASSWORD_VERIFIER` challenge for a user who has set up multifactor authentication, Amazon Cognito follows it up with an `SMS_MFA`, `EMAIL_OTP`, or `SOFTWARE_TOKEN_MFA` challenge. These are the prompts for a multi-factor authentication code. In your function, include handling for input events from `SMS_MFA`, `EMAIL_OTP`, and `SOFTWARE_TOKEN_MFA` challenges. You don't need to invoke any MFA challenges in your define auth challenge function.  
When your function is determining whether a user has successfully authenticated and you should issue them tokens, always check `challengeName` in your define auth challenge function and verify that it matches the expected value.  
**challengeResult**  
Set to `true` if the user successfully completed the challenge, or `false` otherwise.  
**challengeMetadata**  
Your name for the custom challenge. Used only if `challengeName` is `CUSTOM_CHALLENGE`.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the Lambda function that you specify for the define auth challenge trigger. To pass this data to your Lambda function, you can use the `ClientMetadata` parameter in the [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API operations. The request that invokes the define auth challenge function doesn't include data passed in the ClientMetadata parameter in [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) and [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) API operations.

### Define Auth challenge response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-define-auth-challenge-response"></a>

In the response, you can return the next stage of the authentication process.

**challengeName**  
A string that contains the name of the next challenge. If you want to present a new challenge to your user, specify the challenge name here.

**issueTokens**  
If you determine that the user has completed the authentication challenges sufficiently, set to `true`. If the user has not met the challenges sufficiently, set to `false`.

**failAuthentication**  
If you want to end the current authentication process, set to `true`. To continue the current authentication process, set to `false`.

## Define Auth challenge example
<a name="aws-lambda-triggers-define-auth-challenge-example"></a>

This example defines a series of challenges for authentication and issues tokens only if the user has completed all of the challenges successfully. When users complete SRP authentication with the `SRP_A` and `PASSWORD_VERIFIER` challenges, this function passes them a `CUSTOM_CHALLENGE` that invokes the create auth challenge trigger. In combination with our [create auth challenge example](user-pool-lambda-create-auth-challenge.md#aws-lambda-triggers-create-auth-challenge-example), this sequence delivers a CAPTCHA challenge for challenge three and a security question for challenge four.

After the user solves the CAPTCHA and answers the security question, this function confirms that your user pool can issue tokens. SRP authentication isn't required; you can also set the CAPTCHA and security question as challenges one & two. In the case where your define auth challenge function doesn't declare SRP challenges, your users' success is determined entirely by their responses to your custom prompts.

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (
    event.request.session.length === 1 &&
    event.request.session[0].challengeName === "SRP_A"
  ) {
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "PASSWORD_VERIFIER";
  } else if (
    event.request.session.length === 2 &&
    event.request.session[1].challengeName === "PASSWORD_VERIFIER" &&
    event.request.session[1].challengeResult === true
  ) {
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "CUSTOM_CHALLENGE";
  } else if (
    event.request.session.length === 3 &&
    event.request.session[2].challengeName === "CUSTOM_CHALLENGE" &&
    event.request.session[2].challengeResult === true
  ) {
    event.response.issueTokens = false;
    event.response.failAuthentication = false;
    event.response.challengeName = "CUSTOM_CHALLENGE";
  } else if (
    event.request.session.length === 4 &&
    event.request.session[3].challengeName === "CUSTOM_CHALLENGE" &&
    event.request.session[3].challengeResult === true
  ) {
    event.response.issueTokens = true;
    event.response.failAuthentication = false;
  } else {
    event.response.issueTokens = false;
    event.response.failAuthentication = true;
  }

  return event;
};

export { handler };
```

------

# Create Auth challenge Lambda trigger
<a name="user-pool-lambda-create-auth-challenge"></a>

The create auth challenge trigger is a Lambda function that has the details of each challenge declared by the define auth challenge trigger. It processes the challenge name declared by the define auth challenge trigger and returns a `publicChallengeParameters` that your application must present to the user. This function then provides your user pool with the answer to the challenge, `privateChallengeParameters`, that your user pool passes to the verify auth challenge trigger. Where your define auth challenge trigger manages the challenge sequence, your create auth challenge trigger manages the challenge contents.

![\[Challenge Lambda triggers\]](http://docs.aws.amazon.com/cognito/latest/developerguide/images/lambda-challenges2.png)


**Create auth challenge**  
Amazon Cognito invokes this trigger after **Define Auth Challenge** if a custom challenge has been specified as part of the **Define Auth Challenge** trigger. It creates a [custom authentication flow](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow).

This Lambda trigger is invoked to create a challenge to present to the user. The request for this Lambda trigger includes the `challengeName` and `session`. The `challengeName` is a string and is the name of the next challenge to the user. The value of this attribute is set in the Define Auth Challenge Lambda trigger.

The challenge loop will repeat until all challenges are answered.

**Topics**
+ [Create Auth challenge Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-create-auth-challenge)
+ [Create Auth challenge example](#aws-lambda-triggers-create-auth-challenge-example)

## Create Auth challenge Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-create-auth-challenge"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
            . . .
        },
        "challengeName": "string",
        "session": [
            ChallengeResult,
            . . .
        ],
        "clientMetadata": {
            "string": "string",
            . . .
        },
        "userNotFound": boolean
    },
    "response": {
        "publicChallengeParameters": {
            "string": "string",
            . . .
        },
        "privateChallengeParameters": {
            "string": "string",
            . . .
        },
        "challengeMetadata": "string"
    }
}
```

------

### Create Auth challenge request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-create-auth-challenge-request"></a>

**userAttributes**  
One or more name-value pairs representing user attributes.

**userNotFound**  
This boolean is populated when `PreventUserExistenceErrors` is set to `ENABLED` for your User Pool client.

**challengeName**  
The name of the new challenge.

**session**  
The session element is an array of `ChallengeResult` elements, each of which contains the following elements:    
**challengeName**  
The challenge type. One of: `"CUSTOM_CHALLENGE"`, `"PASSWORD_VERIFIER"`, `"SMS_MFA"`, `"DEVICE_SRP_AUTH"`, `"DEVICE_PASSWORD_VERIFIER"`, `"NEW_PASSWORD_REQUIRED"`, or `"ADMIN_NO_SRP_AUTH"`.   
**challengeResult**  
Set to `true` if the user successfully completed the challenge, or `false` otherwise.  
**challengeMetadata**  
Your name for the custom challenge. Used only if `challengeName` is `"CUSTOM_CHALLENGE"`.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the Lambda function that you specify for the create auth challenge trigger. You can use the ClientMetadata parameter in the [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API actions to pass this data to your Lambda function. The request that invokes the create auth challenge function does not include data passed in the ClientMetadata parameter in [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) and [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) API operations.

### Create Auth challenge response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-create-auth-challenge-response"></a>

**publicChallengeParameters**  
One or more key-value pairs for the client app to use in the challenge to be presented to the user. This parameter should contain all of the necessary information to present the challenge to the user accurately.

**privateChallengeParameters**  
This parameter is only used by the Verify Auth Challenge Response Lambda trigger. This parameter should contain all of the information that is required to validate the user's response to the challenge. In other words, the `publicChallengeParameters` parameter contains the question that is presented to the user and `privateChallengeParameters` contains the valid answers for the question.

**challengeMetadata**  
Your name for the custom challenge, if this is a custom challenge.

## Create Auth challenge example
<a name="aws-lambda-triggers-create-auth-challenge-example"></a>

This function has two custom challenges that correspond to the challenge sequence in our [define auth challenge example](user-pool-lambda-define-auth-challenge.md#aws-lambda-triggers-define-auth-challenge-example). The first two challenges are SRP authentication. For the third challenge, this function returns a CAPTCHA URL to your application in the challenge response. Your application renders the CAPTCHA at the given URL and returns the user's input. The URL for the CAPTCHA image is added to the public challenge parameters as "`captchaUrl`", and the expected answer is added to the private challenge parameters.

For the fourth challenge, this function returns a security question. Your application renders the question and prompts the user for their answer. After users solve both custom challenges, the define auth challenge trigger confirms that your user pool can issue tokens.

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (event.request.challengeName !== "CUSTOM_CHALLENGE") {
    return event;
  }

  if (event.request.session.length === 2) {
    event.response.publicChallengeParameters = {};
    event.response.privateChallengeParameters = {};
    event.response.publicChallengeParameters.captchaUrl = "url/123.jpg";
    event.response.privateChallengeParameters.answer = "5";
  }

  if (event.request.session.length === 3) {
    event.response.publicChallengeParameters = {};
    event.response.privateChallengeParameters = {};
    event.response.publicChallengeParameters.securityQuestion =
      "Who is your favorite team mascot?";
    event.response.privateChallengeParameters.answer = "Peccy";
  }

  return event;
};

export { handler };
```

------

# Verify Auth challenge response Lambda trigger
<a name="user-pool-lambda-verify-auth-challenge-response"></a>

The verify auth challenge trigger is a Lambda function that compares a user's provided response to a known answer. This function tells your user pool whether the user answered the challenge correctly. When the verify auth challenge trigger responds with an `answerCorrect` of `true`, the authentication sequence can continue.

![\[Challenge Lambda triggers\]](http://docs.aws.amazon.com/cognito/latest/developerguide/images/lambda-challenges3.png)


**Verify auth challenge response**  
Amazon Cognito invokes this trigger to verify if the response from the user for a custom Auth Challenge is valid or not. It is part of a user pool [custom authentication flow](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow).

The request for this trigger contains the `privateChallengeParameters` and `challengeAnswer` parameters. The Create Auth Challenge Lambda trigger returns `privateChallengeParameters` values, and contains the expected response from the user. The `challengeAnswer` parameter contains the user's response for the challenge.

The response contains the `answerCorrect` attribute. If the user successfully completes the challenge, Amazon Cognito sets the attribute value to `true`. If the user doesn't successfully complete the challenge, Amazon Cognito sets the value to `false`.

The challenge loop repeats until the users answers all challenges.

**Topics**
+ [Verify Auth challenge Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-verify-auth-challenge)
+ [Verify Auth challenge response example](#aws-lambda-triggers-verify-auth-challenge-response-example)

## Verify Auth challenge Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-verify-auth-challenge"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
            . . .
        },
        "privateChallengeParameters": {
            "string": "string",
            . . .
        },
        "challengeAnswer": "string",
        "clientMetadata": {
            "string": "string",
            . . .
        },
        "userNotFound": boolean
    },
    "response": {
        "answerCorrect": boolean
    }
}
```

------

### Verify Auth challenge request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-verify-auth-challenge-request"></a>

**userAttributes**  
This parameter contains one or more name-value pairs that represent user attributes.

**userNotFound**  
When Amazon Cognito sets `PreventUserExistenceErrors` to `ENABLED` for your user pool client, Amazon Cognito populates this Boolean .

**privateChallengeParameters**  
This parameter comes from the Create Auth Challenge trigger. To determine whether the user passed a challenge, Amazon Cognito compares the parameters against a user’s **challengeAnswer**.  
This parameter contains all of the information that is required to validate the user's response to the challenge. That information includes the question that Amazon Cognito presents to the user (`publicChallengeParameters`), and the valid answers for the question (`privateChallengeParameters`). Only the Verify Auth Challenge Response Lambda trigger uses this parameter. 

**challengeAnswer**  
This parameter value is the answer from the user's response to the challenge.

**clientMetadata**  
This parameter contains one or more key-value pairs that you can provide as custom input to the Lambda function for the verify auth challenge trigger. To pass this data to your Lambda function, use the ClientMetadata parameter in the [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API operations. Amazon Cognito doesn't include data from the ClientMetadata parameter in [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) and [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) API operations in the request that it passes to the verify auth challenge function.

### Verify Auth challenge response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-verify-auth-challenge-response"></a>

**answerCorrect**  
If the user successfully completes the challenge, Amazon Cognito sets this parameter to `true`. If the user doesn't successfully complete the challenge, Amazon Cognito sets the parameter to `false`. 

## Verify Auth challenge response example
<a name="aws-lambda-triggers-verify-auth-challenge-response-example"></a>

This verify auth challenge function checks whether the user's response to a challenge matches the expected response. The user's answer is defined by input from your application and the preferred answer is defined by `privateChallengeParameters.answer` in the response from the [create auth challenge trigger response](user-pool-lambda-create-auth-challenge.md#aws-lambda-triggers-create-auth-challenge-example). Both the correct answer and the given answer are part of the input event to this function.

In this example, if the user's response matches the expected response, Amazon Cognito sets the `answerCorrect` parameter to `true`.

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (
    event.request.privateChallengeParameters.answer ===
    event.request.challengeAnswer
  ) {
    event.response.answerCorrect = true;
  } else {
    event.response.answerCorrect = false;
  }

  return event;
};

export { handler };
```

------

# Pre token generation Lambda trigger
<a name="user-pool-lambda-pre-token-generation"></a>

Because Amazon Cognito invokes this trigger before token generation, you can customize the claims in user pool tokens. With the **Basic features** of the version one or `V1_0` pre token generation trigger event, you can customize the identity (ID) token. In user pools with the Essentials or Plus feature plan, you can generate the version two or `V2_0` trigger event with access token customization, and the version three or `V3_0` trigger event with access token customization for machine-to-machine (M2M) client-credentials grants.

Amazon Cognito sends a `V1_0` event as a request to your function with data that it would write to the ID token. A `V2_0` or `V3_0` event is a single request with the data that Amazon Cognito would write to both the identity and access tokens. To customize both tokens, you must update your function to use trigger version two or three, and send data for both tokens in the same response.

Amazon Cognito applies version two event responses to access tokens from user authentication, where a human user has presented credentials to your user pool. Version three event responses apply to access tokens from user authentication and machine authentication, where automated systems authorize access token requests with app client secrets. Aside from the circumstances of the resulting access tokens, version two and three events are identical.

This Lambda trigger can add, remove, and modify some claims in identity and access tokens before Amazon Cognito issues them to your app. To use this feature, associate a Lambda function from the Amazon Cognito user pools console or update your user pool `LambdaConfig` through the AWS Command Line Interface (AWS CLI).

## Event versions
<a name="user-pool-lambda-pre-token-generation-event-versions"></a>

Your user pool can deliver different versions of a pre token generation trigger event to your Lambda function. A `V1_0` trigger delivers the parameters for modification of ID tokens. A `V2_0` or `V3_0` trigger delivers parameters for the following.

1. The functions of a `V1_0` trigger.

1. The ability to customize access tokens.

1. The ability to pass complex datatypes to ID and access token claim values:
   + String
   + Number
   + Boolean
   + Array of strings, numbers, booleans, or a combination of any of these
   + JSON

**Note**  
In the ID token, you can populate complex objects to the values of claims except for `phone_number_verified`, `email_verified`, `updated_at`, and `address`.

User pools deliver `V1_0` events by default. To configure your user pool to send a `V2_0` event, choose a **Trigger event version** of **Basic features \$1 access token customization for user identities** when you configure your trigger in the Amazon Cognito console. To produce `V3_0` events, choose ****Basic features \$1 access token customization for user and machine identities****. You can also set the value of `LambdaVersion` in the [LambdaConfig](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html#CognitoUserPools-UpdateUserPool-request-LambdaConfig) parameters in an [UpdateUserPool ](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html) or [CreateUserPool ](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html) API request. Event versions one, two, and three are available in the **Essentials** and **Plus** feature plans. M2M operations for version three events have a pricing structure separate from the monthly active users (MAU) formula. For more information, see [Amazon Cognito Pricing](https://aws.amazon.com/cognito/pricing/).

**Note**  
User pools that were operational with the **Advanced security features** option on or before November 22, 2024 at 1800 GMT, and that remain on the **Lite** feature tier have access to event versions one and two of the pre token generation trigger. User pools in this legacy tier *without* advanced security features have access to event version one. Version three is *only* available in Essentials and Plus.

## Claims and scopes reference
<a name="user-pool-lambda-pre-token-generation-excluded-claims"></a>

Amazon Cognito limits the claims and scopes that you can add, modify, or suppress in access and identity tokens. The following table describes the claims that your Lambda function can and can't modify, and the trigger event parameters that affect the presence or value of the claim.


| Claim | Default token type | Can add? | Can modify? | Can suppress? | Event parameter - add or modify | Event parameter - suppress | Identity type | Event version | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| Any claim not in the user pool token schema | None | Yes | Yes | N/A | claimsToAddOrOverride | claimsToSuppress | User, machine[1](#cognito-pretoken-machine-ids-tier-note) | All[2](#cognito-pretoken-id-access-versions-note) | 
| scope | Access | Yes | Yes | Yes | scopesToAdd | scopesToSuppress | User, machine[1](#cognito-pretoken-machine-ids-tier-note) | v2\$10, v3\$10 | 
| cognito:groups | ID, Access | Yes | Yes | Yes | groupsToOverride | claimsToSuppress | User | All[2](#cognito-pretoken-id-access-versions-note) | 
| cognito:preferred\$1role | ID | Yes | Yes | Yes | preferredRole | claimsToSuppress[3](#cognito-pretoken-suppress-groups-note) | User | All | 
| cognito:roles | ID | Yes | Yes | Yes | iamRolesToOverride | claimsToSuppress[3](#cognito-pretoken-suppress-groups-note) | User | All | 
| cognito:username | ID | No | No | No | N/A | N/A | User | N/A | 
| Any other claim with a cognito: prefix | None | No | No | No | N/A | N/A | N/A | N/A | 
| username | Access | No | No | No | N/A | N/A | User | v2\$10, v3\$10 | 
| sub | ID, Access | No | No | No | N/A | N/A | User | N/A | 
| standard OIDC attribute | ID | Yes | Yes | Yes | claimsToAddOrOverride | claimsToSuppress | User | All | 
| custom: attribute | ID | Yes | Yes | Yes | claimsToAddOrOverride | claimsToSuppress | User | All | 
| dev: attribute | ID | No | No | Yes | N/A | claimsToSuppress | User | All | 
| identities | ID | No | No | No | N/A | N/A | User | N/A | 
| aud[4](#cognito-pretoken-aud-note) | ID | No | No | No | N/A | N/A | User, machine | N/A | 
| client\$1id | Access | No | No | No | N/A | N/A | User, machine | N/A | 
| event\$1id | Access | No | No | No | N/A | N/A | User, machine | N/A | 
| device\$1key | Access | No | No | No | N/A | N/A | User | N/A | 
| version | Access | No | No | No | N/A | N/A | User, machine | N/A | 
| acr | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| amr | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| at\$1hash | ID | No | No | No | N/A | N/A | User, machine | N/A | 
| auth\$1time | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| azp | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| exp | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| iat | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| iss | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| jti | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| nbf | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| nonce | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| origin\$1jti | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 
| token\$1use | ID, Access | No | No | No | N/A | N/A | User, machine | N/A | 

 1 Access tokens for machine identities are only available with `v3_0` of the trigger input event. Event version three is only available in the **Essentials** and **Plus** feature tiers. User pools on the **Lite** tier can receive `v1_0` events. User pools on the **Lite** tier with advanced security features can receive `v1_0` and `v2_0` events.

2 Configure your pre token generation trigger to event version `v1_0` for ID token only, `v2_0` for ID and access token, `v3_0` for ID and access token with capabilities for machine identities.

 3 To suppress the `cognito:preferred_role` and `cognito:roles` claims, add `cognito:groups` to `claimsToSuppress`.

 4 You can add an `aud` claim to access tokens, but its value must match the app client ID of the current session. You can derive the client ID in the request event from `event.callerContext.clientId`.

## Customizing the identity token
<a name="user-pool-lambda-pre-token-generation-idtoken"></a>

With all event versions of the pre token generation Lambda trigger, you can customize the content of an identity (ID) token from your user pool. The ID token provides user attributes from a trusted identity source for sign-in to a web or mobile app. For more information about ID tokens, see [Understanding the identity (ID) token](amazon-cognito-user-pools-using-the-id-token.md).

The uses of the pre token generation Lambda trigger with an ID token include the following.
+ Make a change at runtime to the IAM role that your user requests from an identity pool.
+ Add user attributes from an external source.
+ Add or replace existing user attribute values.
+ Suppress disclosure of user attributes that, because of your user's authorized scopes and the read access to attributes that you granted to your app client, would otherwise be passed to your app.

## Customizing the access token
<a name="user-pool-lambda-pre-token-generation-accesstoken"></a>

With event versions two and three of the pre token generation Lambda trigger, you can customize the content of an access token from your user pool. The access token authorizes users to retrieve information from access-protected resources like Amazon Cognito token-authorized API operations and third-party APIs. For machine-to-machine (M2M) authorization with a client credentials grant, Amazon Cognito only invokes the pre token generation trigger when your user pool is configured for a version three (`V3_0`) event. For more information about access tokens, see [Understanding the access token](amazon-cognito-user-pools-using-the-access-token.md).

The uses of the pre token generation Lambda trigger with an access token include the following.
+ Add or suppress scopes in the `scope` claim. For example, you can add scopes to an access token that resulted from Amazon Cognito user pools API authentication, which only assigns the scope `aws.cognito.signin.user.admin`.
+ Change a user's membership in user pool groups.
+ Add claims that aren't already present in an Amazon Cognito access token.
+ Suppress disclosure of claims that would otherwise be passed to your app.

To support access customization in your user pool, you must configure the user pool to generate an updated version of the trigger request. Update your user pool as shown in the following procedure.

------
#### [ AWS Management Console ]

**To support access token customization in a pre token generation Lambda trigger**

1. Go to the [Amazon Cognito console](https://console.aws.amazon.com/cognito/home), and then choose **User Pools**.

1. Choose an existing user pool from the list, or [create a user pool](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-as-user-directory.html).

1. Choose the **Extensions** menu and locate **Lambda triggers**.

1. Add or edit a **Pre token generation trigger**.

1. Choose a Lambda function under **Assign Lambda function**. 

1. Choose a **Trigger event version** of **Basic features \$1 access token customization for user identities** or **Basic features \$1 access token customization for user and machine identities**. This setting updates the request parameters that Amazon Cognito sends to your function to include fields for access token customization.

------
#### [ User pools API ]

**To support access token customization in a pre token generation Lambda trigger**

Generate a [CreateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html) or [UpdateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html) API request. You must specify a value for all parameters that you don't want set to a default value. For more information, see [Updating user pool and app client configuration](cognito-user-pool-updating.md).

Include the following content in the `LambdaVersion` parameter of your request. A `LambdaVersion` value of `V2_0` causes your user pool to add parameters for, and apply changes to, access tokens. A `LambdaVersion` value of `V3_0` produces the same event as `V2_0`, but causes your user pool to *also* apply changes to M2M access tokens. To invoke a specific function version, use a Lambda function ARN with a function version as the value of `LambdaArn`.

```
"PreTokenGenerationConfig": { 
   "LambdaArn": "arn:aws:lambda:us-west-2:123456789012:function:MyFunction",
   "LambdaVersion": "V3_0"
},
```

------

**Client metadata for machine-to-machine (M2M) client credentials**  
You can pass [client metadata](cognito-user-pools-working-with-lambda-triggers.md#working-with-lambda-trigger-client-metadata) in M2M requests. Client metadata is additional information from a user or application environment that can contribute to the outcomes of a [Pre token generation Lambda trigger](#user-pool-lambda-pre-token-generation). In authentication operations with a user principal, you can pass client metadata to the pre token generation trigger in the body of [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API requests. Because applications conduct the flow for generation of access tokens for M2M with direct requests to the [Token endpoint](token-endpoint.md), they have a different model. In the POST body of token requests for client credentials, pass an `aws_client_metadata` parameter with the client metadata object URL-encoded (`x-www-form-urlencoded`) to string. For an example request, see [Client credentials with basic authorizationClient credentials with POST body authorization](token-endpoint.md#exchanging-client-credentials-for-an-access-token-in-request-body). The following is an example parameter that passes the key-value pairs `{"environment": "dev", "language": "en-US"}`.

```
aws_client_metadata=%7B%22environment%22%3A%20%22dev%22,%20%22language%22%3A%20%22en-US%22%7D
```

**More resources**
+ [How to customize access tokens in Amazon Cognito user pools](https://aws.amazon.com/blogs/security/how-to-customize-access-tokens-in-amazon-cognito-user-pools/)

**Topics**
+ [Event versions](#user-pool-lambda-pre-token-generation-event-versions)
+ [Claims and scopes reference](#user-pool-lambda-pre-token-generation-excluded-claims)
+ [Customizing the identity token](#user-pool-lambda-pre-token-generation-idtoken)
+ [Customizing the access token](#user-pool-lambda-pre-token-generation-accesstoken)
+ [Pre token generation Lambda trigger sources](#user-pool-lambda-pre-token-generation-trigger-source)
+ [Pre token generation Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-pre-token-generation)
+ [Pre token trigger event version two example: Add and suppress claims, scopes, and groups](#aws-lambda-triggers-pre-token-generation-example-version-2-overview)
+ [Pre token generation event version two example: Add claims with complex objects](#aws-lambda-triggers-pre-token-generation-example-version-2-complex-objects)
+ [Pre token generation event version one example: Add a new claim and suppress an existing claim](#aws-lambda-triggers-pre-token-generation-version-1-add-claim)
+ [Pre token generation event version one example: Modify the user's group membership](#aws-lambda-triggers-pre-token-generation-version-1-change-group)

## Pre token generation Lambda trigger sources
<a name="user-pool-lambda-pre-token-generation-trigger-source"></a>


| triggerSource value | Event | 
| --- | --- | 
| TokenGeneration\$1HostedAuth | Called during authentication from the Amazon Cognito managed login sign-in page. | 
| TokenGeneration\$1Authentication | Called after user authentication flows have completed. | 
| TokenGeneration\$1NewPasswordChallenge | Called after the user is created by an admin. This flow is invoked when the user has to change a temporary password. | 
| TokenGeneration\$1ClientCredentials | Called after an M2M client credentials grant. Your user pool only sends this event when your event version is V3\$10. | 
| TokenGeneration\$1AuthenticateDevice | Called at the end of the authentication of a user device. | 
| TokenGeneration\$1RefreshTokens | Called when a user tries to refresh the identity and access tokens. | 

## Pre token generation Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-token-generation"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests. When you add a pre token generation Lambda trigger to your user pool, you can choose a trigger version. This version determines whether Amazon Cognito passes a request to your Lambda function with additional parameters for access-token customization.

------
#### [ Version one ]

The version one token can set group membership, IAM roles, and new claims in ID tokens. Group membership overrides also apply to the `cognito:groups` claim in access tokens.

```
{
    "request": {
        "userAttributes": {"string": "string"},
        "groupConfiguration": {
                "groupsToOverride": [
                    "string",
                    "string"
                ],
                "iamRolesToOverride": [
                    "string",
                    "string"
                ],
                "preferredRole": "string"
        },
        "clientMetadata": {"string": "string"}
    },
    "response": {
        "claimsOverrideDetails": {
            "claimsToAddOrOverride": {"string": "string"},
            "claimsToSuppress": [
                "string",
                "string"
            ],
            "groupOverrideDetails": {
                "groupsToOverride": [
                    "string",
                    "string"
                ],
                "iamRolesToOverride": [
                    "string",
                    "string"
                ],
                "preferredRole": "string"
            }
        }
    }
}
```

------
#### [ Versions two and three ]

The versions two and three request events add fields that customize the access token. User pools apply changes from version three events to access tokens for machine identities. These versions also add support for complex `claimsToOverride` data types in the response object. Your Lambda function can return the following types of data in the value of `claimsToOverride`:
+ String
+ Number
+ Boolean
+ Array of strings, numbers, booleans, or a combination of any of these
+ JSON

```
{
    "request": {
        "userAttributes": {
            "string": "string"
        },
        "scopes": ["string", "string"],
        "groupConfiguration": {
            "groupsToOverride": ["string", "string"],
            "iamRolesToOverride": ["string", "string"],
            "preferredRole": "string"
        },
        "clientMetadata": {
            "string": "string"
        }
    },
    "response": {
        "claimsAndScopeOverrideDetails": {
            "idTokenGeneration": {
                "claimsToAddOrOverride": {
                    "string": [accepted datatype]
                },
                "claimsToSuppress": ["string", "string"]
            },
            "accessTokenGeneration": {
                "claimsToAddOrOverride": {
                    "string": [accepted datatype]
                },
                "claimsToSuppress": ["string", "string"],
                "scopesToAdd": ["string", "string"],
                "scopesToSuppress": ["string", "string"]
            },
            "groupOverrideDetails": {
                "groupsToOverride": ["string", "string"],
                "iamRolesToOverride": ["string", "string"],
                "preferredRole": "string"
            }
        }
    }
}
```

------

### Pre token generation request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-token-generation-request"></a>


| Name | Description | Minimum trigger event version | 
| --- |--- |--- |
| userAttributes |  The attributes of your user's profile in your user pool.  | 1 | 
| groupConfiguration |  The input object that contains the current group configuration. The object includes `groupsToOverride`, `iamRolesToOverride`, and `preferredRole`.  | 1 | 
| groupsToOverride |  The [user pool groups](cognito-user-pools-user-groups.md#cognito-user-pools-user-groups.title) that your user is a member of.  | 1 | 
| iamRolesToOverride |  You can associate a user pool group with an AWS Identity and Access Management (IAM) role. This element is a list of all IAM roles from the groups that your user is a member of.  | 1 | 
| preferredRole |  You can set a [precedence](cognito-user-pools-user-groups.md#assigning-precedence-values-to-groups.title) for user pool groups. This element contains the name of the IAM role from the group with the highest precendence in the `groupsToOverride` element.  | 1 | 
| clientMetadata |  One or more key-value pairs that you can specify and provide as custom input to the Lambda function for the pre token generation trigger. To pass this data to your Lambda function, use the ClientMetadata parameter in the [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API operations. Amazon Cognito doesn't include data from the `ClientMetadata` parameter in [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) and [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) API operations in the request that it passes to the pre token generation function.  | 1 | 
| scopes |  Access token scopes. The scopes that are present in an access token are the user pool standard and custom scopes that your user requested, and that you authorized your app client to issue.  | 2 | 

### Pre token generation response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-pre-token-generation-response"></a>


| Name | Description | Minimum trigger event version | 
| --- |--- |--- |
| claimsOverrideDetails | A container for all elements in a V1\$10 trigger event. | 1 | 
| claimsAndScopeOverrideDetails |  A container for all elements in a `V2_0` or `V3_0` trigger event.  | 2 | 
| idTokenGeneration |  The claims that you want to override, add, or suppress in your user’s ID token. This parent to ID token customization values appears only in event version 2 and above, but the child elements appear in version 1 events.  | 2 | 
| accessTokenGeneration |  The claims and scopes that you want to override, add, or suppress in your user’s access token. This parent to access token customization values appears only in event version 2 and above.  | 2 | 
| claimsToAddOrOverride |  A map of one or more claims and their values that you want to add or modify. For group-related claims, use `groupOverrideDetails` instead. In event version 2 and above, this element appears under both `accessTokenGeneration` and `idTokenGeneration`.  | 1[*](#cognito-pretoken-complex-objects-note) | 
| claimsToSuppress |  A list of claims that you want Amazon Cognito to suppress. If your function both suppresses and replaces a claim value, then Amazon Cognito suppresses the claim. In event version 2 and above, this element appears under both `accessTokenGeneration` and `idTokenGeneration`.  | 1 | 
| groupOverrideDetails |  The output object that contains the current group configuration. The object includes `groupsToOverride`, `iamRolesToOverride`, and `preferredRole`. Your function replaces the `groupOverrideDetails` object with the object that you provide. If you provide an empty or null object in the response, then Amazon Cognito suppresses the groups. To keep the existing group configuration the same, copy the value of the `groupConfiguration` object of the request to the `groupOverrideDetails` object in the response. Then pass it back to the service. Amazon Cognito ID and access tokens both contain the `cognito:groups` claim. Your `groupOverrideDetails` object replaces the `cognito:groups` claim in access tokens and ID tokens. Group overrides are the only changes to the access token that version 1 events can make.  | 1 | 
| scopesToAdd |  A list of scopes that you want to add to the `scope` claim in your user's access token. You can't add scope values that contain one or more blank-space characters.  | 2 | 
| scopesToSuppress |  A list of scopes that you want to remove from the `scope` claim in your user's access token.  | 2 | 

 \$1 Response objects to version one events can return strings. Response objects to version two and three events can return [complex objects](#user-pool-lambda-pre-token-generation-event-versions).

## Pre token trigger event version two example: Add and suppress claims, scopes, and groups
<a name="aws-lambda-triggers-pre-token-generation-example-version-2-overview"></a>

This example makes the following modifications to a user's tokens.

1. Sets their `family_name` as `Doe` in the ID token.

1. Prevents `email` and `phone_number` claims from appearing in the ID token.

1. Sets their ID token `cognito:roles` claim to `"arn:aws:iam::123456789012:role\/sns_callerA","arn:aws:iam::123456789012:role\/sns_callerC","arn:aws:iam::123456789012:role\/sns_callerB"`.

1. Sets their ID token `cognito:preferred_role` claim to `arn:aws:iam::123456789012:role/sns_caller`.

1. Adds the scopes `openid`, `email`, and `solar-system-data/asteroids.add` to the access token.

1. Suppresses the scope `phone_number` and `aws.cognito.signin.user.admin` from the access token. Removal of `phone_number` prevents retrieval of the user's phone number from `userInfo`. Removal of `aws.cognito.signin.user.admin` prevents API requests by the user to read and modify their own profile with the Amazon Cognito user pools API.
**Note**  
The removal of `phone_number` from scopes only prevents retrieval of a user's phone number if the remaining scopes in the access token include `openid` and at least one more standard scope. For more information, see [About scopes](cognito-user-pools-define-resource-servers.md#cognito-user-pools-define-resource-servers-about-scopes).

1. Sets their ID and access token `cognito:groups` claim to `"new-group-A","new-group-B","new-group-C"`.

------
#### [ JavaScript ]

```
export const handler = function(event, context) {
  event.response = {
    "claimsAndScopeOverrideDetails": {
      "idTokenGeneration": {
        "claimsToAddOrOverride": {
          "family_name": "Doe"
        },
        "claimsToSuppress": [
          "email",
          "phone_number"
        ]
      },
      "accessTokenGeneration": {
        "scopesToAdd": [
          "openid",
          "email",
          "solar-system-data/asteroids.add"
        ],
        "scopesToSuppress": [
          "phone_number",
          "aws.cognito.signin.user.admin"
        ]
      },
      "groupOverrideDetails": {
        "groupsToOverride": [
          "new-group-A",
          "new-group-B",
          "new-group-C"
        ],
        "iamRolesToOverride": [
          "arn:aws:iam::123456789012:role/new_roleA",
          "arn:aws:iam::123456789012:role/new_roleB",
          "arn:aws:iam::123456789012:role/new_roleC"
        ],
        "preferredRole": "arn:aws:iam::123456789012:role/new_role",
      }
    }
  };
  // Return to Amazon Cognito
  context.done(null, event);
};
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
    "version": "2",
    "triggerSource": "TokenGeneration_Authentication",
    "region": "us-east-1",
    "userPoolId": "us-east-1_EXAMPLE",
    "userName": "JaneDoe",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "1example23456789"
    },
    "request": {
        "userAttributes": {
            "sub": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
            "cognito:user_status": "CONFIRMED",
            "email_verified": "true",
            "phone_number_verified": "true",
            "phone_number": "+12065551212",
            "family_name": "Zoe",
            "email": "Jane.Doe@example.com"
        },
        "groupConfiguration": {
            "groupsToOverride": ["group-1", "group-2", "group-3"],
            "iamRolesToOverride": ["arn:aws:iam::123456789012:role/sns_caller1", "arn:aws:iam::123456789012:role/sns_caller2", "arn:aws:iam::123456789012:role/sns_caller3"],
            "preferredRole": ["arn:aws:iam::123456789012:role/sns_caller"]
        },
        "scopes": [
            "aws.cognito.signin.user.admin", "openid", "email", "phone"
        ]
    },
    "response": {
        "claimsAndScopeOverrideDetails": []
    }
}
```

------

## Pre token generation event version two example: Add claims with complex objects
<a name="aws-lambda-triggers-pre-token-generation-example-version-2-complex-objects"></a>

This example makes the following modifications to a user's tokens.

1. Adds claims of number, string, boolean, and JSON types to the ID token. This is the only change that version two trigger events makes available to the ID token.

1. Adds claims of number, string, boolean, and JSON types to the access token.

1. Adds three scopes to the access token.

1. Suppresses the `email` claim in the ID and access tokens.

1. Suppresses the `aws.cognito.signin.user.admin` scope in the access token.

------
#### [ JavaScript ]

```
export const handler = function(event, context) {

    var scopes = ["MyAPI.read", "MyAPI.write", "MyAPI.admin"]
    var claims = {}
    claims["aud"]= event.callerContext.clientId;
    claims["booleanTest"] = false;
    claims["longTest"] = 9223372036854775807;
    claims["exponentTest"] = 1.7976931348623157E308;
    claims["ArrayTest"] = ["test", 9223372036854775807, 1.7976931348623157E308, true];
    claims["longStringTest"] = "\{\
        \"first_json_block\": \{\
            \"key_A\": \"value_A\",\
            \"key_B\": \"value_B\"\
        \},\
        \"second_json_block\": \{\
            \"key_C\": \{\
                \"subkey_D\": [\
                    \"value_D\",\
                    \"value_E\"\
                ],\
                \"subkey_F\": \"value_F\"\
            \},\
            \"key_G\": \"value_G\"\
        \}\
    \}";
    claims["jsonTest"] = {
    	"first_json_block": {
    		"key_A": "value_A",
    		"key_B": "value_B"
    	},
    	"second_json_block": {
    		"key_C": {
    			"subkey_D": [
    				"value_D",
    				"value_E"
    			],
    			"subkey_F": "value_F"
    		},
    		"key_G": "value_G"
    	}
    };
    event.response = {
        "claimsAndScopeOverrideDetails": {
            "idTokenGeneration": {
                "claimsToAddOrOverride": claims,
                "claimsToSuppress": ["email"]
            },
            "accessTokenGeneration": {
                "claimsToAddOrOverride": claims,
                "claimsToSuppress": ["email"],
                "scopesToAdd": scopes,
                "scopesToSuppress": ["aws.cognito.signin.user.admin"]
            }
        }
    };
    console.info("EVENT response\n" + JSON.stringify(event, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2))
    console.info("EVENT response size\n" + JSON.stringify(event, (_, v) => typeof v === 'bigint' ? v.toString() : v).length)
    // Return to Amazon Cognito
    context.done(null, event);
};
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
    "version": "2",
    "triggerSource": "TokenGeneration_HostedAuth",
    "region": "us-west-2",
    "userPoolId": "us-west-2_EXAMPLE",
    "userName": "JaneDoe",
    "callerContext": {
        "awsSdkVersion": "aws-sdk-unknown-unknown",
        "clientId": "1example23456789"
    },
    "request": {
        "userAttributes": {
            "sub": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
            "cognito:user_status": "CONFIRMED"
            "email_verified": "true",
            "phone_number_verified": "true",
            "phone_number": "+12065551212",
            "email": "Jane.Doe@example.com"
        },
        "groupConfiguration": {
            "groupsToOverride": ["group-1", "group-2", "group-3"],
            "iamRolesToOverride": ["arn:aws:iam::123456789012:role/sns_caller1"],
            "preferredRole": ["arn:aws:iam::123456789012:role/sns_caller1"]
        },
        "scopes": [
            "aws.cognito.signin.user.admin",
            "phone",
            "openid",
            "profile",
            "email"
        ]
    },
    "response": {
        "claimsAndScopeOverrideDetails": []
    }
}
```

------

## Pre token generation event version one example: Add a new claim and suppress an existing claim
<a name="aws-lambda-triggers-pre-token-generation-version-1-add-claim"></a>

This example uses a version 1 trigger event with a pre token generation Lambda function to add a new claim and suppresses an existing claim.

------
#### [ Node.js ]

```
const handler = async (event) => {
  event.response = {
    claimsOverrideDetails: {
      claimsToAddOrOverride: {
        my_first_attribute: "first_value",
        my_second_attribute: "second_value",
      },
      claimsToSuppress: ["email"],
    },
  };

  return event;
};

export { handler };
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample: Because the code example doesn't process any request parameters, you can use a test event with an empty request. For more information about common request parameters, see [User pool Lambda trigger event](cognito-user-pools-working-with-lambda-triggers.md#cognito-user-pools-lambda-trigger-event-parameter-shared).

------
#### [ JSON ]

```
{
  "request": {},
  "response": {}
}
```

------

## Pre token generation event version one example: Modify the user's group membership
<a name="aws-lambda-triggers-pre-token-generation-version-1-change-group"></a>

This example uses a version 1 trigger event with a pre token generation Lambda function to modify the user's group membership.

------
#### [ Node.js ]

```
const handler = async (event) => {
  event.response = {
    claimsOverrideDetails: {
      groupOverrideDetails: {
        groupsToOverride: ["group-A", "group-B", "group-C"],
        iamRolesToOverride: [
          "arn:aws:iam::XXXXXXXXXXXX:role/sns_callerA",
          "arn:aws:iam::XXXXXXXXX:role/sns_callerB",
          "arn:aws:iam::XXXXXXXXXX:role/sns_callerC",
        ],
        preferredRole: "arn:aws:iam::XXXXXXXXXXX:role/sns_caller",
      },
    },
  };

  return event;
};

export { handler };
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
  "request": {},
  "response": {}
}
```

------

# Migrate user Lambda trigger
<a name="user-pool-lambda-migrate-user"></a>

When a user doesn't exist in the user pool at sign-in with a password, or in the forgot-password flow, Amazon Cognito invokes this trigger. After the Lambda function returns successfully, Amazon Cognito creates the user in the user pool. For details on the authentication flow with the user migration Lambda trigger, see [Importing users with a user migration Lambda trigger](cognito-user-pools-import-using-lambda.md).

To migrate users from your existing user directory into Amazon Cognito user pools at sign-in, or during the forgot-password flow, use this Lambda trigger.

**Topics**
+ [Migrate user Lambda trigger sources](#user-pool-lambda-migrate-user-trigger-source)
+ [Migrate user Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-user-migration)
+ [Example: Migrate a user with an existing password](#aws-lambda-triggers-user-migration-example-1)

## Migrate user Lambda trigger sources
<a name="user-pool-lambda-migrate-user-trigger-source"></a>


| triggerSource value | Event | 
| --- | --- | 
| UserMigration\$1Authentication[1](#cognito-migrate-user-passwordless-note) | User migration at sign-in. | 
| UserMigration\$1ForgotPassword | User migration during forgot-password flow. | 

1 Amazon Cognito doesn't invoke this trigger when users authenticate with [passwordless sign-in](amazon-cognito-user-pools-authentication-flow-methods.md#amazon-cognito-user-pools-authentication-flow-methods-passwordless).

## Migrate user Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-user-migration"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "userName": "string",
    "request": {
        "password": "string",
        "validationData": {
            "string": "string",
            . . .
        },
        "clientMetadata": {
            "string": "string",
      	. . .
        }
    },
    "response": {
        "userAttributes": {
            "string": "string",
            . . .
        },
        "finalUserStatus": "string",
        "messageAction": "string",
        "desiredDeliveryMediums": [ "string", . . .],
        "forceAliasCreation": boolean,
        "enableSMSMFA": boolean
    }
}
```

------

### Migrate user request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-user-migration-request"></a>

**userName**  
The username that the user enters at sign-in.

**password**  
The password that the user enters at sign-in. Amazon Cognito doesn't send this value in a request that's initiated by a forgot-password flow.

**validationData**  
One or more key-value pairs that contain the validation data in the user's sign-in request. To pass this data to your Lambda function, you can use the ClientMetadata parameter in the [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) and [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) API actions.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the Lambda function for the migrate user trigger. To pass this data to your Lambda function, you can use the ClientMetadata parameter in the [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [ForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html) API actions.

### Migrate user response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-user-migration-response"></a>

**userAttributes**  
This field is required.   
This field must contain one or more name-value pairs that Amazon Cognito stores in the user profile in your user pool and uses as user attributes. You can include both standard and custom user attributes. Custom attributes require the `custom:` prefix to distinguish them from standard attributes. For more information, see [Custom attributes](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-custom-attributes.html).  
To reset their passwords in the forgot-password flow, a user must have either a verified email address or a verified phone number. Amazon Cognito sends a message containing a reset password code to the email address or phone number in the user attributes.     
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html)

**finalUserStatus**  
You can set this parameter to `CONFIRMED` to auto-confirm your users so that they can sign in with their previous passwords. When you set a user to `CONFIRMED`, they do not need to take additional action before they can sign in. If you don't set this attribute to `CONFIRMED`, it's set to `RESET_REQUIRED`.  
A `finalUserStatus` of `RESET_REQUIRED` means that the user must change their password immediately after migration at sign-in, and your client app must handle the `PasswordResetRequiredException` during the authentication flow.  
Amazon Cognito doesn't enforce the password strength policy that you configured for the user pool during migration using Lambda trigger. If the password doesn't meet the password policy that you configured, Amazon Cognito still accepts the password so that it can continue to migrate the user. To enforce password strength policy and reject passwords that don't meet the policy, validate the password strength in your code. Then, if the password doesn't meet the policy, set finalUserStatus to `RESET_REQUIRED`.

**messageAction**  
You can set this parameter to `SUPPRESS` to decline to send the welcome message that Amazon Cognito usually sends to new users. If your function doesn't return this parameter, Amazon Cognito sends the welcome message.

**desiredDeliveryMediums**  
You can set this parameter to `EMAIL` to send the welcome message by email, or `SMS` to send the welcome message by SMS. If your function doesn't return this parameter, Amazon Cognito sends the welcome message by SMS.

**forceAliasCreation**  
If you set this parameter to `TRUE` and the phone number or email address in the UserAttributes parameter already exists as an alias with a different user, the API call migrates the alias from the previous user to the newly created user. The previous user can no longer log in using that alias.  
If you set this parameter to `FALSE` and the alias exists, Amazon Cognito doesn't migrate the user and returns an error to the client app.  
If you don't return this parameter, Amazon Cognito assumes its value is "false".

**enableSMSMFA**  
Set this parameter to `true` to require that your migrated user complete SMS text message multi-factor authentication (MFA) to sign in. Your user pool must have MFA enabled. Your user's attributes in the request parameters must include a phone number, or else the migration of that user will fail.

## Example: Migrate a user with an existing password
<a name="aws-lambda-triggers-user-migration-example-1"></a>

This example Lambda function migrates the user with an existing password and suppresses the welcome message from Amazon Cognito.

------
#### [ Node.js ]

```
exports.handler = (event, context, callback) => {
  var user;

  if (event.triggerSource == "UserMigration_Authentication") {
    // authenticate the user with your existing user directory service
    user = authenticateUser(event.userName, event.request.password);
    if (user) {
      event.response.userAttributes = {
        email: user.emailAddress,
        email_verified: "true",
      };
      event.response.finalUserStatus = "CONFIRMED";
      event.response.messageAction = "SUPPRESS";
      context.succeed(event);
    } else {
      // Return error to Amazon Cognito
      callback("Bad password");
    }
  } else if (event.triggerSource == "UserMigration_ForgotPassword") {
    // Lookup the user in your existing user directory service
    user = lookupUser(event.userName);
    if (user) {
      event.response.userAttributes = {
        email: user.emailAddress,
        // required to enable password-reset code to be sent to user
        email_verified: "true",
      };
      event.response.messageAction = "SUPPRESS";
      context.succeed(event);
    } else {
      // Return error to Amazon Cognito
      callback("Bad password");
    }
  } else {
    // Return error to Amazon Cognito
    callback("Bad triggerSource " + event.triggerSource);
  }
};
```

------

# Custom message Lambda trigger
<a name="user-pool-lambda-custom-message"></a>

When you have an external standard for the email and SMS messages that you want to send to your users, or when you want to apply your own logic at runtime to the formatting of user messages, add a custom message trigger to your user pool. The custom message Lambda receives the contents of all email and SMS messages before your user pool sends them. Your Lambda function then has the opportunity to modify the message contents and subject.

Amazon Cognito invokes this trigger before it sends an email or phone verification message or a multi-factor authentication (MFA) code. You can customize the message dynamically with your custom message trigger.

The request includes `codeParameter`. This is a string that acts as a placeholder for the code that Amazon Cognito delivers to the user. Insert the `codeParameter` string into the message body where you want the verification code to appear. When Amazon Cognito receives this response, Amazon Cognito replaces the `codeParameter` string with the actual verification code. 

**Note**  
The input event for a custom message Lambda function with the `CustomMessage_AdminCreateUser` trigger source includes a username and verification code. Because an admin-created user must receive both their user name and code, the response from your function must include placeholder variables for the username and code. The placeholders for your message are the values of `request.usernameParameter` and `request.codeParameter`. These values are typically `{username}` and `{####}`; as a best practice, reference the input values instead of hardcoding the variable names.

**Topics**
+ [Custom message Lambda trigger sources](#cognito-user-pools-lambda-trigger-syntax-custom-message-trigger-source)
+ [Custom message Lambda trigger parameters](#cognito-user-pools-lambda-trigger-syntax-custom-message)
+ [Custom message for sign-up example](#aws-lambda-triggers-custom-message-example)
+ [Custom message for admin create user example](#aws-lambda-triggers-custom-message-admin-example)

## Custom message Lambda trigger sources
<a name="cognito-user-pools-lambda-trigger-syntax-custom-message-trigger-source"></a>


| triggerSource value | Event | 
| --- | --- | 
| CustomMessage\$1SignUp | Custom message – To send the confirmation code post sign-up. | 
| CustomMessage\$1AdminCreateUser | Custom message – To send the temporary password to a new user. | 
| CustomMessage\$1ResendCode | Custom message – To resend the confirmation code to an existing user. | 
| CustomMessage\$1ForgotPassword | Custom message – To send the confirmation code for Forgot Password request. | 
| CustomMessage\$1UpdateUserAttribute | Custom message – When a user's email or phone number is changed, this trigger sends a verification code automatically to the user. Cannot be used for other attributes. | 
| CustomMessage\$1VerifyUserAttribute | Custom message – This trigger sends a verification code to the user when they manually request it for a new email or phone number. | 
| CustomMessage\$1Authentication | Custom message – To send MFA code during authentication. | 

## Custom message Lambda trigger parameters
<a name="cognito-user-pools-lambda-trigger-syntax-custom-message"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "userAttributes": {
            "string": "string",
            . . .
        }
        "codeParameter": "####",
        "usernameParameter": "string",
        "clientMetadata": {
            "string": "string",
            . . .
        }
    },
    "response": {
        "smsMessage": "string",
        "emailMessage": "string",
        "emailSubject": "string"
    }
}
```

------

### Custom message request parameters
<a name="cognito-user-pools-lambda-trigger-syntax-custom-message-request"></a>

**userAttributes**  
One or more name-value pairs representing user attributes.

**codeParameter**  
A string for you to use as the placeholder for the verification code in the custom message.

**usernameParameter**  
The user name. Amazon Cognito includes this parameter in requests that result from admin-created users.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the Lambda function that you specify for the custom message trigger. The request that invokes a custom message function doesn't include data passed in the ClientMetadata parameter in [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) and [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) API operations. To pass this data to your Lambda function, you can use the ClientMetadata parameter in the following API actions:  
+  [AdminResetUserPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminResetUserPassword.html) 
+  [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) 
+  [AdminUpdateUserAttributes](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminUpdateUserAttributes.html)
+  [ForgotPassword](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ForgotPassword.html)
+  [GetUserAttributeVerificationCode](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_GetUserAttributeVerificationCode.html)
+  [ResendConfirmationCode](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ResendConfirmationCode.html)
+  [SignUp](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SignUp.html)
+  [UpdateUserAttributes](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserAttributes.html)

### Custom message response parameters
<a name="cognito-user-pools-lambda-trigger-syntax-custom-message-response"></a>

In the response, specify the custom text to use in messages to your users. For the string constraints that Amazon Cognito applies to these parameters, see [MessageTemplateType](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_MessageTemplateType.html).

**smsMessage**  
The custom SMS message to be sent to your users. Must include the `codeParameter` value that you received in the request.

**emailMessage**  
The custom email message to send to your users. You can use HTML formatting in the `emailMessage` parameter. Must include the `codeParameter` value that you received in the request as the variable `{####}`. Amazon Cognito can use the `emailMessage` parameter only if the `EmailSendingAccount` attribute of the user pool is `DEVELOPER`. If the `EmailSendingAccount` attribute of the user pool isn't `DEVELOPER` and an `emailMessage` parameter is returned, Amazon Cognito generates a 400 error code `com.amazonaws.cognito.identity.idp.model.InvalidLambdaResponseException`. When you choose Amazon Simple Email Service (Amazon SES) to send email messages, the `EmailSendingAccount` attribute of a user pool is `DEVELOPER`. Otherwise, the value is `COGNITO_DEFAULT`.

**emailSubject**  
The subject line for the custom message. You can only use the `emailSubject` parameter if the EmailSendingAccount attribute of the user pool is `DEVELOPER`. If the `EmailSendingAccount` attribute of the user pool isn't `DEVELOPER` and Amazon Cognito returns an `emailSubject` parameter, Amazon Cognito generates a 400 error code `com.amazonaws.cognito.identity.idp.model.InvalidLambdaResponseException`. The `EmailSendingAccount` attribute of a user pool is `DEVELOPER` when you choose to use Amazon Simple Email Service (Amazon SES) to send email messages. Otherwise, the value is `COGNITO_DEFAULT`.

## Custom message for sign-up example
<a name="aws-lambda-triggers-custom-message-example"></a>

This example Lambda function customizes an email or SMS message when the service requires an app to send a verification code to the user.

Amazon Cognito can invoke a Lambda trigger at multiple events: post-registration, resending a verification code, recovering a forgotten password, or verifying a user attribute. The response includes messages for both SMS and email. The message must include the code parameter `"####"`. This parameter is the placeholder for the verification code that the user receives.

The maximum length for an email message is 20,000 UTF-8 characters,. This length includes the verification code. You can use HTML tags in these email messages.

The maximum length of SMS messages is 140 UTF-8 characters. This length includes the verification code.

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (event.triggerSource === "CustomMessage_SignUp") {
    const message = `Thank you for signing up. Your confirmation code is ${event.request.codeParameter}.`;
    event.response.smsMessage = message;
    event.response.emailMessage = message;
    event.response.emailSubject = "Welcome to the service.";
  }
  return event;
};

export { handler };
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
	"version": "1",
	"region": "us-west-2",
	"userPoolId": "us-west-2_EXAMPLE",
	"userName": "test-user",
	"callerContext": {
		"awsSdkVersion": "aws-sdk-unknown-unknown",
		"clientId": "1example23456789"
	},
	"triggerSource": "CustomMessage_SignUp",
	"request": {
		"userAttributes": {
			"sub": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
			"cognito:user_status": "CONFIRMED",
			"email_verified": "true",
			"phone_number_verified": "true",
			"phone_number": "+12065551212",
			"email": "test-user@example.com"
		},
		"codeParameter": "{####}",
		"linkParameter": "{##Click Here##}",
		"usernameParameter": "None"
	},
	"response": {
		"smsMessage": "None",
		"emailMessage": "None",
		"emailSubject": "None"
	}
}
```

------

## Custom message for admin create user example
<a name="aws-lambda-triggers-custom-message-admin-example"></a>

The request that Amazon Cognito sent to this example custom message Lambda function has a `triggerSource` value of `CustomMessage_AdminCreateUser` and a username and temporary password. The function populates `${event.request.codeParameter}` from the temporary password in the request, and `${event.request.usernameParameter}` from the username in the request.

Your custom messages must insert the values of `codeParameter` and `usernameParameter` into `smsMessage` and `emailMessage` in the response object. In this example, the function writes the same message to the response fields `event.response.smsMessage` and `event.response.emailMessage`.

The maximum length of an email message is 20,000 UTF-8 characters. This length includes the verification code. You can use HTML tags in these emails. The maximum length of SMS messages is 140 UTF-8 characters. This length includes the verification code.

The response includes messages for both SMS and email. 

------
#### [ Node.js ]

```
const handler = async (event) => {
  if (event.triggerSource === "CustomMessage_AdminCreateUser") {
    const message = `Welcome to the service. Your user name is ${event.request.usernameParameter}. Your temporary password is ${event.request.codeParameter}`;
    event.response.smsMessage = message;
    event.response.emailMessage = message;
    event.response.emailSubject = "Welcome to the service";
  }
  return event;
};

export { handler };
```

------

Amazon Cognito passes event information to your Lambda function. The function then returns the same event object to Amazon Cognito, with any changes in the response. In the Lambda console, you can set up a test event with data that is relevant to your Lambda trigger. The following is a test event for this code sample:

------
#### [ JSON ]

```
{
  "version": 1,
  "triggerSource": "CustomMessage_AdminCreateUser",
  "region": "<region>",
  "userPoolId": "<userPoolId>",
  "userName": "<userName>",
  "callerContext": {
      "awsSdk": "<calling aws sdk with version>",
      "clientId": "<apps client id>",
      ...
  },
  "request": {
      "userAttributes": {
          "phone_number_verified": false,
          "email_verified": true,
           ...
      },
      "codeParameter": "####",
      "usernameParameter": "username"
  },
  "response": {
      "smsMessage": "<custom message to be sent in the message with code parameter and username parameter>"
      "emailMessage": "<custom message to be sent in the message with code parameter and username parameter>"
      "emailSubject": "<custom email subject>"
  }
}
```

------

# Custom sender Lambda triggers
<a name="user-pool-lambda-custom-sender-triggers"></a>

The Lambda triggers `CustomEmailSender` and `CustomSMSSender` support third-party email and SMS notifications in user pools. You can choose SMS and email providers to send notifications to users from within your Lambda function code. When Amazon Cognito sends invitations, MFA codes, confirmation codes, verification codes, and temporary passwords to users, the events activate your configured Lambda functions. Amazon Cognito sends the code and temporary passwords (secrets) to your activated Lambda functions. Amazon Cognito encrypts these secrets with an AWS KMS customer managed key and the AWS Encryption SDK. The AWS Encryption SDK is a client-side encryption library that helps you to encrypt and decrypt generic data.

**[CustomEmailSender](user-pool-lambda-custom-email-sender.md)**  
Amazon Cognito invokes this trigger to send email notifications to users. 

**[CustomSMSSender](user-pool-lambda-custom-sms-sender.md)**  
Amazon Cognito invokes this trigger to send SMS notifications to users.

## Encryption concepts
<a name="user-pool-lambda-custom-sender-triggers-resources"></a>

Amazon Cognito doesn't send users' codes in plaintext in the events that it sends to custom sender triggers. The Lambda functions must decrypt codes in the events. The following concepts are the encryption architecture that your function must use to get codes that it can deliver to users.

**AWS KMS**  
AWS KMS is a managed service to create and control AWS KMS keys. These keys encrypt your data. For more information see, [What is AWS Key Management Service?](/kms/latest/developerguide/overview.html).

**KMS key**  
A KMS key is a logical representation of a cryptographic key. The KMS key includes metadata, such as the key ID, creation date, description, and key state. The KMS key also contains the key material used to encrypt and decrypt data. For more information see, [AWS KMS keys](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#kms_keys).

**Symmetric KMS key**  
A symmetric KMS key is a 256-bit encryption key that doesn't exit AWS KMS unencrypted. To use a symmetric KMS key, you must call AWS KMS. Amazon Cognito uses symmetric keys. The same key encrypts and decrypts. For more information see, [Symmetric KMS keys](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#symmetric-cmks). 

## Things to know about custom sender Lambda triggers
<a name="user-pool-lambda-custom-sender-triggers-things-to-know"></a>
+ To configure your user pools to use these Lambda triggers, you can use the AWS CLI or SDK. These configurations aren't available from Amazon Cognito console.

  The `UpdateUserPool` operation sets Lambda configuration. Requests to this operation require all the parameters of your user pool *and* the parameters that you want to change. If you don't provide all relevant parameters, Amazon Cognito sets the values of any missing parameters to their defaults. As demonstrated in the AWS CLI example that follows, include entries for all Lambda functions that you want to add to or keep in your user pool. For more information, see [Updating user pool and app client configuration](cognito-user-pool-updating.md).

  ```
      #Send this parameter in an 'aws cognito-idp update-user-pool' CLI command, including any existing 
      #user pool configurations. This snippet also includes a pre sign-up trigger for syntax reference. The pre sign-up trigger
      #doesn't have a role in custom sender triggers.
                
        --lambda-config "PreSignUp=lambda-arn, \
                         CustomSMSSender={LambdaVersion=V1_0,LambdaArn=lambda-arn}, \
                         CustomEmailSender={LambdaVersion=V1_0,LambdaArn=lambda-arn}, \
                         KMSKeyID=key-id"
  ```

  For requests that use the JSON body of `UpdateUserPool` the following `LambdaConfig` snippet assigns custom SMS and email sender functions.

  ```
  "LambdaConfig": {
     "KMSKeyID": "arn:aws:kms:us-east-1:111122223333:key/a6c4f8e2-0c45-47db-925f-87854bc9e357",
     "CustomEmailSender": {
        "LambdaArn": "arn:aws:lambda:us-east-1:111122223333:function:MyFunction",
        "LambdaVersion": "V1_0"
     },
     "CustomSMSSender": {
        "LambdaArn": "arn:aws:lambda:us-east-1:111122223333:function:MyFunction",
        "LambdaVersion": "V1_0"
     }
  ```
+ To remove a custom sender Lambda trigger with an `update-user-pool` AWS CLI command, omit the `CustomSMSSender` or `CustomEmailSender` parameter from `--lambda-config`, and include all other triggers that you want to use with your user pool.

  To remove a custom sender Lambda trigger with an `UpdateUserPool` API request, omit the `CustomSMSSender` or `CustomEmailSender` parameter from the request body that contains the rest of your user pool configuration.
+ Amazon Cognito HTML-escapes reserved characters like `<` (`&lt;`) and `>` (`&gt;`) in your user's temporary password. These characters might appear in temporary passwords that Amazon Cognito sends to your custom email sender function, but don't appear in temporary verification codes. To send temporary passwords, your Lambda function must unescape these characters after it decrypts the password, and before it sends the message to your user.

## Activating custom sender Lambda triggers
<a name="enable-custom-sender-lambda-trigger"></a>

To use custom logic to send SMS or email messages for your user pool, set up custom sender triggers. The following procedure assigns a custom SMS trigger, a custom email trigger, or both to your user pool. After you add your custom sender trigger, Amazon Cognito always sends user attributes, including the phone number, and the one-time code to your Lambda function instead of the default behavior that sends an SMS or email message.

1. Create a [symmetric encryption key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#symmetric-cmks) in AWS Key Management Service (AWS KMS). Amazon Cognito generates secrets—temporary passwords, verification codes, authentication one-time passwords, and confirmation codes—then uses this KMS key to encrypt the secrets with [AWS Encryption SDK](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html). You can then use the AWS Encryption SDK in your Lambda function to decrypt the secrets and send them to the user in plaintext.

1. The IAM principal that creates or updates your user pool creates a one-time grant against the KMS key that Amazon Cognito uses to encrypt the code. Grant this principal `CreateGrant` permissions for your KMS key. For this example KMS key policy to be effective, the administrator who updates the user pool must be signed in with an assumed-role session for the IAM role `arn:aws:iam::111222333444:role/my-example-administrator-role`. 

   Apply the following resource-based policy, modified for your environment, to your KMS key.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
       {
           "Effect": "Allow",
           "Principal": {
               "AWS": "arn:aws:iam::111122223333:role/my-example-administrator-role"
           },
           "Action": "kms:CreateGrant",
           "Resource": "arn:aws:kms:us-west-2:111122223333:key/1example-2222-3333-4444-999example",
           "Condition": {
               "StringEquals": {
                  "kms:EncryptionContext:userpool-id": "us-west-2_EXAMPLE"
               }
           }
       },
       {
           "Sid": "Allow Lambda to decrypt",
           "Effect": "Allow",
           "Principal": {
               "AWS": "arn:aws:iam::111122223333:role/my-lambda-function-role"
           },
           "Action": "kms:Decrypt",
           "Resource": "*"
       }]
   }
   ```

------

1. Create a Lambda function for the custom sender trigger. Amazon Cognito uses the [AWS encryption SDK](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html) to encrypt the secrets, temporary passwords and codes that authorize your users' API requests.

   1. Assign a [Lambda execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html) that has, at minimum, `kms:Decrypt` permissions for your KMS key.

   1. Compose Lambda function code to send your messages. The input event to your function contains a secret. In your function, decrypt the secret with the AWS Encryption SDK and process any relevant metadata. Then send the code, your own custom message, and destination phone number to the custom API that delivers your message.

   1. Add the AWS Encryption SDK to your Lambda function. For more information, see [AWS Encryption SDK programming languages](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/programming-languages.html). To update the Lambda package, complete the following steps.

      1. Export your Lambda function as a .zip file in the AWS Management Console.

      1. Open your function and add the AWS Encryption SDK. For more information and download links, see [AWS Encryption SDK programming languages](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/programming-languages.html) in the *AWS Encryption SDK Developer Guide*.

      1. Zip your function with your SDK dependencies, and upload the function to Lambda. For more information, see [Deploying Lambda functions as .zip file archives](https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-zip.html#configuration-function-create) in the *AWS Lambda Developer Guide*.

1. Grant Amazon Cognito service principal `cognito-idp.amazonaws.com` access to invoke the Lambda function.

   The following AWS CLI command grants Amazon Cognito permission to invoke your Lambda function:

   ```
   aws lambda add-permission --function-name lambda_arn --statement-id "CognitoLambdaInvokeAccess" --action lambda:InvokeFunction --principal cognito-idp.amazonaws.com
   ```

1. Generate an [UpdateUserPool](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html) API request with a `LambdaConfig` parameter that adds custom sender Lambda triggers. You can't add triggers of this type in the Amazon Cognito console. Custom sender triggers require `LambdaConfig` parameters of `KMSKeyID` and `CustomSMSSender` or `CustomEmailSender` (or both).

# Custom email sender Lambda trigger
<a name="user-pool-lambda-custom-email-sender"></a>

When you assign a custom email sender trigger to your user pool, Amazon Cognito invokes a Lambda function instead of its default behavior when a user event requires that it send an email message. With a custom sender trigger, your AWS Lambda function can send email notifications to your users through a method and provider that you choose. The custom code of your function must process and deliver all email messages from your user pool.

This trigger serves scenarios where you might want to have greater control over how your user pool sends email messages. Your Lambda function can customize the call to Amazon SES API operations, for example when you want to manage multiple verified identities or cross AWS Regions. Your function also might redirect messages to another delivery medium or third-party service.

To learn how to configure a custom email sender trigger, see [Activating custom sender Lambda triggers](user-pool-lambda-custom-sender-triggers.md#enable-custom-sender-lambda-trigger).

## Custom email sender Lambda trigger sources
<a name="trigger-source"></a>

The following table shows the triggering events for custom email trigger sources in your Lambda code.


| `TriggerSource value` | Event | 
| --- | --- | 
| CustomEmailSender\$1SignUp | A user signs up and Amazon Cognito sends a welcome message. | 
| CustomEmailSender\$1Authentication | A user signs in and Amazon Cognito sends an email OTP or MFA code. | 
| CustomEmailSender\$1ForgotPassword | A user requests a code to reset their password. | 
| CustomEmailSender\$1ResendCode | A user requests a replacement account-confirmation code. | 
| CustomEmailSender\$1UpdateUserAttribute | A user updates an email address or phone number attribute and Amazon Cognito sends a code to verify the attribute. | 
| CustomEmailSender\$1VerifyUserAttribute | A user creates a new email address or phone number attribute and Amazon Cognito sends a code to verify the attribute. | 
| CustomEmailSender\$1AdminCreateUser | You create a new user in your user pool and Amazon Cognito sends them a temporary password. | 
| CustomEmailSender\$1AccountTakeOverNotification | Amazon Cognito detects an attempt to take over a user account and sends the user a notification. | 

## Custom email sender Lambda trigger parameters
<a name="custom-email-sender-parameters"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "type": "customEmailSenderRequestV1",
        "code": "string",
        "clientMetadata": {
            "string": "string",
             . . .
            },
        "userAttributes": {
            "string": "string",
            . . .
         }
}
```

------

### Custom email sender request parameters
<a name="custom-email-sender-request-parameters"></a>

**type**  
The request version. For a custom email sender event, the value of this string is always `customEmailSenderRequestV1`.

**code**  
The encrypted code that your function can decrypt and send to your user.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the custom email sender Lambda function trigger. To pass this data to your Lambda function, you can use the ClientMetadata parameter in the [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API actions. Amazon Cognito doesn't include data from the ClientMetadata parameter in [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) and [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) API operations in the request that it passes to the post authentication function.  
Amazon Cognito sends `ClientMetadata` to custom email trigger functions in events with the following trigger sources:  
+ `CustomEmailSender_ForgotPassword`
+ `CustomEmailSender_SignUp`
+ `CustomEmailSender_Authentication`
Amazon Cognito doesn't send `ClientMetadata` in trigger events with source `CustomEmailSender_AccountTakeOverNotification`.

**userAttributes**  
One or more key-value pairs that represent user attributes.

### Custom email sender response parameters
<a name="custom-email-sender-response-parameters"></a>

Amazon Cognito doesn't expect any additional return information in the custom email sender response. Your Lambda function must interpret the event and decrypt the code, then deliver the message contents. A typical function assembles an email message and directs it to a third-party SMTP relay.

## Code example
<a name="custom-email-sender-code-examples"></a>

The following Node.js example processes an email message event in your custom email sender Lambda function. This example assumes your function has two environment variables defined.

**`KEY_ID`**  
The ID of the KMS key that you want to use to encrypt and decrypt your users' codes.

**`KEY_ARN`**  
The Amazon Resource Name (ARN) of the KMS key that you want to use to encrypt and decrypt your users' codes.

**To deploy this function**

1. Install the latest version of NodeJS in your developer workspace.

1. Create a new NodeJS project in your workspace.

1. Initialize your project with `npm init -y`.

1. Create the script for the Lambda function: `touch index.mjs`.

1. Paste the contents of the below example into `index.mjs`.

1. Download the project dependency, AWS Encryption SDK: `npm install @aws-crypto/client-node`.

1. Zip the project directory into a file: `zip -r my_deployment_package.zip .`.

1. [Deploy the ZIP file to your function](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-package.html).

This example function decrypts the code and, for sign-up events, simulates sending an email message to the user's email address.

```
import { KmsKeyringNode, buildClient, CommitmentPolicy } from '@aws-crypto/client-node';

// Configure the encryption SDK client with the KMS key from the environment variables
const { encrypt, decrypt } = buildClient(
    CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
);

const generatorKeyId = process.env.KEY_ID;
const keyIds = [process.env.KEY_ARN];
const keyring = new KmsKeyringNode({ generatorKeyId, keyIds });

// Example function to simulate sending email.
// This example logs message details to CloudWatch Logs from your Lambda function.
// Update this function with custom logic that sends an email message to 'emailaddress' with body 'message'.
const sendEmail = async (emailAddress, message) => {
    // Log the destination with the email address masked.
    console.log(`Simulating email send to ${emailAddress.replace(/[^@.]/g, '*')}`);
    // Log the message with the code masked.
    console.log(`Message content: ${message.replace(/\b\d{6,8}\b/g, '********')}`);
    // Simulate API delay
    await new Promise(resolve => setTimeout(resolve, 100));
    console.log('Email sent successfully');
    return true;
};

export const handler = async (event) => {
    try {
        // Decrypt the secret code using encryption SDK
        let plainTextCode;
        if (event.request.code) {
            const { plaintext, messageHeader } = await decrypt(keyring, Buffer.from(event.request.code, 'base64'));
            plainTextCode = Buffer.from(plaintext).toString('utf-8');
        }

        // Handle different trigger sources
        if (event.triggerSource == 'CustomEmailSender_SignUp') {
            const emailAddress = event.request.userAttributes.email;
            const message = `Welcome! Your verification code is: ${plainTextCode}`;
            await sendEmail(emailAddress, message);
        }
        else if (event.triggerSource == 'CustomEmailSender_ResendCode') {
            // Handle resend code
        }
        else if (event.triggerSource == 'CustomEmailSender_ForgotPassword') {
            // Handle forgot password
        }
        else if (event.triggerSource == 'CustomEmailSender_UpdateUserAttribute') {
            // Handle update attribute
        }
        else if (event.triggerSource == 'CustomEmailSender_VerifyUserAttribute') {
            // Handle verify attribute
        }
        else if (event.triggerSource == 'CustomEmailSender_AdminCreateUser') {
            // Handle admin create user
        }
        else if (event.triggerSource == 'CustomEmailSender_Authentication') {
            // Handle authentication
        }
        else if (event.triggerSource == 'CustomEmailSender_AccountTakeOverNotification') {
            // Handle account takeover notification
        }

        return;
    } catch (error) {
        console.error('Error in custom email sender:', error);
        throw error;
    }
};
```

# Custom SMS sender Lambda trigger
<a name="user-pool-lambda-custom-sms-sender"></a>

When you assign a custom SMS sender trigger to your user pool, Amazon Cognito invokes a Lambda function instead of its default behavior when a user event requires that it send an SMS message. With a custom sender trigger, your AWS Lambda function can send SMS notifications to your users through a method and provider that you choose. The custom code of your function must process and deliver all SMS messages from your user pool.

This trigger serves scenarios where you might want to have greater control over how your user pool sends SMS messages. Your Lambda function can customize the call to Amazon SNS API operations, for example when you want to manage multiple origination IDs or cross AWS Regions. Your function also might redirect messages to another delivery medium or third-party service.

To learn how to configure a custom email sender trigger, see [Activating custom sender Lambda triggers](user-pool-lambda-custom-sender-triggers.md#enable-custom-sender-lambda-trigger).

## Custom SMS sender Lambda trigger sources
<a name="trigger-source"></a>

The following table shows the triggering event for custom SMS trigger sources in your Lambda code.


| `TriggerSource value` | Event | 
| --- | --- | 
| CustomSMSSender\$1SignUp | A user signs up and Amazon Cognito sends a welcome message. | 
| CustomSMSSender\$1ForgotPassword | A user requests a code to reset their password. | 
| CustomSMSSender\$1ResendCode | A user requests a new code to confirm their registration. | 
| CustomSMSSender\$1VerifyUserAttribute | A user creates a new email address or phone number attribute and Amazon Cognito sends a code to verify the attribute. | 
| CustomSMSSender\$1UpdateUserAttribute | A user updates an email address or phone number attribute and Amazon Cognito sends a code to verify the attribute. | 
| CustomSMSSender\$1Authentication | A user signs in and Amazon Cognito sends an SMS OTP or MFA code. | 
| CustomSMSSender\$1AdminCreateUser | You create a new user in your user pool and Amazon Cognito sends them a temporary password. | 

## Custom SMS sender Lambda trigger parameters
<a name="custom-sms-sender-parameters"></a>

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the [common parameters](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-working-with-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-shared) that Amazon Cognito adds to all requests.

------
#### [ JSON ]

```
{
    "request": {
        "type": "customSMSSenderRequestV1",
        "code": "string",
        "clientMetadata": {
            "string": "string",
             . . .
            },
        "userAttributes": {
            "string": "string",
            . . .
         }
}
```

------

### Custom SMS sender request parameters
<a name="custom-sms-sender-request-parameters"></a>

**type**  
The request version. For a custom SMS sender event, the value of this string is always `customSMSSenderRequestV1`.

**code**  
The encrypted code that your function can decrypt and send to your user.

**clientMetadata**  
One or more key-value pairs that you can provide as custom input to the custom SMS sender Lambda function trigger. To pass this data to your Lambda function, you can use the ClientMetadata parameter in the [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) and [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) API actions. Amazon Cognito doesn't include data from the ClientMetadata parameter in [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) and [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) API operations in the request that it passes to the post authentication function.

**userAttributes**  
One or more key-value pairs that represent user attributes.

### Custom SMS sender response parameters
<a name="custom-sms-sender-response-parameters"></a>

Amazon Cognito doesn't expect any additional return information in the response. Your function can use API operations to query and modify your resources, or record event metadata to an external system.

## Code example
<a name="custom-sms-sender-code-examples"></a>

The following Node.js example processes an SMS message event in your custom SMS sender Lambda function. This example assumes your function has two environment variables defined.

**`KEY_ID`**  
The ID of the KMS key that you want to use to encrypt and decrypt your users' codes.

**`KEY_ARN`**  
The Amazon Resource Name (ARN) of the KMS key that you want to use to encrypt and decrypt your users' codes.

**To deploy this function**

1. Install the latest version of NodeJS in your developer workspace.

1. Create a new NodeJS project in your workspace.

1. Initialize your project with `npm init -y`.

1. Create the script for the Lambda function: `touch index.mjs`.

1. Paste the contents of the below example into `index.mjs`.

1. Download the project dependency, AWS Encryption SDK: `npm install @aws-crypto/client-node`.

1. Zip the project directory into a file: `zip -r my_deployment_package.zip .`.

1. [Deploy the ZIP file to your function](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-package.html).

```
import { KmsKeyringNode, buildClient, CommitmentPolicy } from '@aws-crypto/client-node';

// Configure the encryption SDK client with the KMS key from the environment variables
const { encrypt, decrypt } = buildClient(
    CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
);

const generatorKeyId = process.env.KEY_ID;
const keyIds = [process.env.KEY_ARN];
const keyring = new KmsKeyringNode({ generatorKeyId, keyIds });

// Example function to simulate sending SMS.
// This example logs message details to CloudWatch Logs from your Lambda function.
// Update this function with custom logic that sends an SMS message to 'phoneNumber' with body 'message'.
const sendSMS = async (phoneNumber, message) => {
    // Log the destination with the phone number masked.
    console.log(`Simulating SMS send to ${phoneNumber.replace(/[^+]/g, '*')}`);
    // Log the message with the code masked.
    console.log(`Message content: ${message.replace(/\b\d{6,8}\b/g, '********')}`);    
    // Simulate API delay
    await new Promise(resolve => setTimeout(resolve, 100));
    console.log('SMS sent successfully');
    return true;
};

export const handler = async (event) => {
    try {
        // Decrypt the secret code using encryption SDK
        let plainTextCode;
        if (event.request.code) {
            const { plaintext, messageHeader } = await decrypt(keyring, Buffer.from(event.request.code, 'base64'));
            plainTextCode = Buffer.from(plaintext).toString('utf-8');
        }

        // Handle different trigger sources
        if (event.triggerSource == 'CustomSMSSender_SignUp') {
            const phoneNumber = event.request.userAttributes.phone_number;
            const message = `Welcome! Your verification code is: ${plainTextCode}`;
            await sendSMS(phoneNumber, message);
        }
        else if (event.triggerSource == 'CustomSMSSender_ResendCode') {
            // Handle resend code
        }
        else if (event.triggerSource == 'CustomSMSSender_ForgotPassword') {
            // Handle forgot password
        }
        else if (event.triggerSource == 'CustomSMSSender_UpdateUserAttribute') {
            // Handle update attribute
        }
        else if (event.triggerSource == 'CustomSMSSender_VerifyUserAttribute') {
            // Handle verify attribute
        }
        else if (event.triggerSource == 'CustomSMSSender_AdminCreateUser') {
            // Handle admin create user
        }
        return;
    } catch (error) {
        console.error('Error in custom SMS sender:', error);
        throw error;
    }
};
```

**Topics**
+ [Custom SMS sender Lambda trigger sources](#trigger-source)
+ [Custom SMS sender Lambda trigger parameters](#custom-sms-sender-parameters)
+ [Code example](#custom-sms-sender-code-examples)
+ [Evaluate SMS message capabilities with a custom SMS sender function](#sms-to-email-example)

## Evaluate SMS message capabilities with a custom SMS sender function
<a name="sms-to-email-example"></a>

A custom SMS sender Lambda function accepts the SMS messages that your user pool would send, and the function delivers the content based on your custom logic. Amazon Cognito sends the [Custom SMS sender Lambda trigger parameters](#custom-sms-sender-parameters) to your function. Your function can do what you want with this information. For example, you can send the code to an Amazon Simple Notification Service (Amazon SNS) topic. An Amazon SNS topic subscriber can be an SMS message, an HTTPS endpoint, or an email address.

To create a test environment for Amazon Cognito SMS messaging with a custom SMS sender Lambda function, see [amazon-cognito-user-pool-development-and-testing-with-sms-redirected-to-email](https://github.com/aws-samples/amazon-cognito-user-pool-development-and-testing-with-sms-redirected-to-email) in the [aws-samples library on GitHub](https://github.com/aws-samples). The repository contains AWS CloudFormation templates that can create a new user pool, or work with a user pool that you already have. These templates create Lambda functions and an Amazon SNS topic. The Lambda function that the template assigns as a custom SMS sender trigger, redirects your SMS messages to the subscribers to the Amazon SNS topic. 

When you deploy this solution to a user pool, all messages that Amazon Cognito usually sends through SMS messaging, the Lambda function instead sends to a central email address. Use this solution to customize and preview SMS messages, and to test the user pool events that cause Amazon Cognito to send an SMS message. After you complete your tests, roll back the CloudFormation stack, or remove the custom SMS sender function assignment from your user pool.

**Important**  
Don't use the templates in [amazon-cognito-user-pool-development-and-testing-with-sms-redirected-to-email](https://github.com/aws-samples/amazon-cognito-user-pool-development-and-testing-with-sms-redirected-to-email) to build a production environment. The custom SMS sender Lambda function in the solution *simulates* SMS messages, but the Lambda function sends them all to a single central email address. Before you can send SMS messages in a production Amazon Cognito user pool, you must complete the requirements shown at [SMS message settings for Amazon Cognito user pools](user-pool-sms-settings.md).