Custom email sender Lambda trigger - Amazon Cognito
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

Custom email sender Lambda trigger

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 Amazon 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.

Note

Currently, you can't assign custom sender triggers in the Amazon Cognito console. You can assign a trigger with the LambdaConfig parameter in a CreateUserPool or UpdateUserPool API request.

To set up this trigger, perform the following steps:

  1. Create a symmetric encryption key in Amazon Key Management Service (Amazon KMS). Amazon Cognito generates secrets—temporary passwords, verification codes, and confirmation codes—then uses this KMS key to encrypt the secrets. You can then use the Decrypt API operation in your Lambda function to decrypt the secrets and send them to the user in plaintext. The Amazon Encryption SDK is a useful tool for Amazon KMS operations in your function.

  2. Create a Lambda function that you want to assign as your custom sender trigger. Grant kms:Decrypt permissions for your KMS key to the Lambda function role.

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

  4. Write Lambda function code that directs your messages to custom delivery methods or third-party providers. To deliver your user's verification or confirmation code, Base64 decode and decrypt the value of the code parameter in the request. This operation produces a plaintext code or password that you must include in your message.

  5. Update the user pool so that it uses a custom sender Lambda trigger. The IAM principal that updates or creates a user pool with a custom sender trigger must have permission to create a grant for your KMS key. The following LambdaConfig snippet assigns custom SMS and email sender functions.

    "LambdaConfig": { "KMSKeyID": "arn:aws:kms:us-east-1:123456789012:key/a6c4f8e2-0c45-47db-925f-87854bc9e357", "CustomEmailSender": { "LambdaArn": "arn:aws:lambda:us-east-1:123456789012:function:MyFunction", "LambdaVersion": "V1_0" }, "CustomSMSSender": { "LambdaArn": "arn:aws:lambda:us-east-1:123456789012:function:MyFunction", "LambdaVersion": "V1_0" }

Custom email sender Lambda trigger parameters

The request that Amazon Cognito passes to this Lambda function is a combination of the parameters below and the common parameters that Amazon Cognito adds to all requests.

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

Custom email sender request parameters

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 and RespondToAuthChallenge API actions. Amazon Cognito doesn't include data from the ClientMetadata parameter in AdminInitiateAuth and InitiateAuth 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 email sender response parameters

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

Activating the custom email sender Lambda trigger

To set up a custom email sender trigger that uses custom logic to send email messages for your user pool, activate the trigger as follows. The procedure that follows assigns a custom email trigger, a custom SMS trigger, or both to your user pool. After you add your custom email sender trigger, Amazon Cognito always sends user attributes, including the email address, and the one-time code to your Lambda function when it would have otherwise sent an email message with Amazon Simple Email Service.

Important

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.

  1. Create an encryption key in Amazon KMS. This key encrypts temporary passwords and authorization codes that Amazon Cognito generates. You can then decrypt these secrets in the custom sender Lambda function and send them to your user in plaintext.

  2. Grant Amazon Cognito service principal cognito-idp.amazonaws.com access to encrypt codes with the KMS key.

    Apply the following resource-based policy to your KMS key.

    { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": "cognito-idp.amazonaws.com" }, "Action": "kms:CreateGrant", "Resource": "arn:aws:kms:us-west-2:111222333444:key/1example-2222-3333-4444-999example", "Condition": { "StringEquals": { "aws:SourceAccount": "111222333444" }, "ArnLike": { "aws:SourceArn": "arn:aws:cognito-idp:us-west-2:111222333444:userpool/us-east-1_EXAMPLE" } } }] }
  3. Create a Lambda function for the custom sender trigger. Amazon Cognito uses the Amazon encryption SDK to encrypt the secrets, temporary passwords and codes that authorize your users' API requests.

    1. Assign an IAM role to your Lambda function that has, at minimum, kms:Decrypt permissions for your KMS key.

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

    The following Amazon 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
  5. Compose your Lambda function code to send your messages. Amazon Cognito uses Amazon Encryption SDK to encrypt secrets before Amazon Cognito sends the secrets to the custom sender Lambda function. In your function, decrypt the secret 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.

  6. Add the Amazon Encryption SDK to your Lambda function. For more information, see Amazon Encryption SDK programming languages. To update the Lambda package, complete the following steps.

    1. Export your Lambda function as a .zip file in the Amazon Web Services Management Console.

    2. Open your function and add the Amazon Encryption SDK. For more information and download links, see Amazon Encryption SDK programming languages in the Amazon Encryption SDK Developer Guide.

    3. Zip your function with your SDK dependencies, and upload the function to Lambda. For more information, see Deploying Lambda functions as .zip file archives in the Amazon Lambda Developer Guide.

  7. Update your user pool to add custom sender Lambda triggers. Include a CustomSMSSender or CustomEmailSender parameter in an UpdateUserPool API request. The UpdateUserPool API operation requires 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 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 configuration.

    #Send this parameter in an 'aws cognito-idp update-user-pool' CLI command, including any existing #user pool configurations. --lambda-config "PreSignUp=lambda-arn, \ CustomSMSSender={LambdaVersion=V1_0,LambdaArn=lambda-arn}, \ CustomEmailSender={LambdaVersion=V1_0,LambdaArn=lambda-arn}, \ KMSKeyID=key-id"

To remove a custom sender Lambda trigger with an update-user-pool Amazon CLI, 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.

Code example

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_ALIAS

The alias 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.

const AWS = require('aws-sdk'); const b64 = require('base64-js'); const encryptionSdk = require('@aws-crypto/client-node'); //Configure the encryption SDK client with the KMS key from the environment variables. const { encrypt, decrypt } = encryptionSdk.buildClient(encryptionSdk.CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT); const generatorKeyId = process.env.KEY_ALIAS; const keyIds = [ process.env.KEY_ARN ]; const keyring = new encryptionSdk.KmsKeyringNode({ generatorKeyId, keyIds }) exports.handler = async (event) => { //Decrypt the secret code using encryption SDK. let plainTextCode; if(event.request.code){ const { plaintext, messageHeader } = await decrypt(keyring, b64.toByteArray(event.request.code)); plainTextCode = plaintext } //PlainTextCode now contains the decrypted secret. if(event.triggerSource == 'CustomEmailSender_SignUp'){ //Send an email message to your user via a custom provider. //Include the temporary password in the message. } else if(event.triggerSource == 'CustomEmailSender_ResendCode'){ } else if(event.triggerSource == 'CustomEmailSender_ForgotPassword'){ } else if(event.triggerSource == 'CustomEmailSender_UpdateUserAttribute'){ } else if(event.triggerSource == 'CustomEmailSender_VerifyUserAttribute'){ } else if(event.triggerSource == 'CustomEmailSender_AdminCreateUser'){ } else if(event.triggerSource == 'CustomEmailSender_AccountTakeOverNotification'){ } return; };

Custom email sender Lambda trigger sources

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

TriggerSource value Event
CustomEmailSender_SignUp A user signs up and Amazon Cognito sends a welcome message.
CustomEmailSender_ForgotPassword A user requests a code to reset their password.
CustomEmailSender_ResendCode A user requests a replacement code to reset their password.
CustomEmailSender_UpdateUserAttribute A user updates an email address or phone number attribute and Amazon Cognito sends a code to verify the attribute.
CustomEmailSender_VerifyUserAttribute A user creates a new email address or phone number attribute and Amazon Cognito sends a code to verify the attribute.
CustomEmailSender_AdminCreateUser You create a new user in your user pool and Amazon Cognito sends them a temporary password.
CustomEmailSender_AccountTakeOverNotification Amazon Cognito detects an attempt to take over a user account and sends the user a notification.