AWS Cognito: Send email by using a third-party provider
AWS Cognito: Custom Email Sender Lambda Trigger
AWS Cognito is a user authorization and authentication service offered by AWS. It provides you with many options for sign-up and sign-in functionalities. You can customize your authentication process using AWS lambda functions as triggers in Cognito. One of the important triggers AWS Cognito provides is the Custom email sender Lambda trigger. Amazon Cognito invokes the custom email sender trigger as part of the sign-up, forgot password, update or verify user attribute, create a user via admin API, etc. It is mainly used where you want a third-party provider or custom methods to send email notifications to your users from your AWS Lambda function code. So, get ready to dive deep into setting up your custom email sender trigger.
Let’s get started
Below architecture diagram shows the functioning of the ‘Custom Email Sender Lambda Trigger’ and trigger configuration. The main components of the architecture are the Cognito user pool, KMS Key, and the lambda function. Whenever a user sends a request, the Cognito user pool sends an encrypted verification code with the help of the KMS key to the lambda function. The lambda function implements logic to send an email via a third-party provider or custom method.
KMS key configuration
To begin with, create a symmetric encryption key in AWS Key Management Service (KMS). When Cognito generates authentication codes for multifactor authentication (MFA) or temporary passwords, it uses this key to encrypt them. These are passed to the lambda function. While sending the code to the user, you can decrypt them using AWS SDK.
Cognito service should be able to access our KMS key. From the AWS console, in the key policy, grant Amazon Cognito service principal cognito-idp.amazonaws.com
access to encrypt codes with the KMS key.
Lambda function as a trigger
Now create a lambda function you want to assign as a custom trigger. It handles sending authentication codes in emails via third-party providers or custom methods.
As mentioned above, Cognito generates an encrypted authentication code using the KMS key created. In the use case where you want to send the authentication code to the user by email, you need to decrypt it by using AWS SDK
before sending. Below JavaScript
code snippet can be used as a reference for this :
const AWS = require('aws-sdk');
const b64 = require('base64-js');
const encryptionSdk = require('@aws-crypto/client-node');
const { encrypt, decrypt } = encryptionSdk.buildClient(encryptionSdk.CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT);
const generatorKeyId = process.env.KEY_ALIAS; // environment variable for alias of the key
const keyIds = [ process.env.KEY_ARN ]; // ARN of the key
const keyring = new encryptionSdk.KmsKeyringNode({ generatorKeyId, keyIds })
//Decrypt the secret code using encryption SDK.
let verificationCode;
if(event.request.code){
const { plaintext, messageHeader } = await decrypt(keyring, b64.toByteArray(event.request.code));
verificationCode = plaintext
}
Grant Amazon Cognito service access to invoke the Lambda function. You can use the below command for this:
aws lambda add-permission --function-name {lambda_arn} --statement-id "invokePermissions" --action lambda:InvokeFunction --principal cognito-idp.amazonaws.com
In the AWS console of the lambda function, you can verify the above permission in the Permissions section of the configuration tab.
This trigger can be used in various functionalities like the sign-up process, forgot password flow, update or verify attributes, etc. The source of the trigger is passed in the parameter ‘triggerSource’
in the input event of the lambda function. Below code snippet shows an example of handling the source of the event.
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'){
//A user requests a replacement code to reset their password.
}
else if(event.triggerSource == 'CustomEmailSender_ForgotPassword'){
//A user requests a code to reset their password.
}
else if(event.triggerSource == 'CustomEmailSender_UpdateUserAttribute'){
//A user updates an email address or phone number attribute and
//Amazon Cognito sends a code to verify the attribute.
}
else if(event.triggerSource == 'CustomEmailSender_VerifyUserAttribute'){
//A user creates a new email address or phone number attribute and
//Amazon Cognito sends a code to verify the attribute.
}
else if(event.triggerSource == 'CustomEmailSender_AdminCreateUser'){
//You create a new user in your user pool and
//Amazon Cognito sends them a temporary password.
}
else if(event.triggerSource == 'CustomEmailSender_AccountTakeOverNotification'){
//Amazon Cognito detects an attempt to take over a user account and
//sends the user a notification.
}
We can use this trigger in the use case of the sign-up journey, where you’re fetching email Ids from a different source and don’t want to save them in the Cognito user pool. You must set some dummy email IDs in the user pool in the signup process. In the lambda function, fetch the actual email Id and send an email via a custom method. Below architecture diagram shows us the configuration of this scenario.
Trigger configuration
The next step is to add a custom sender Lambda trigger to your user pool. Please note: currently, you can’t assign a custom email sender trigger in the Amazon Cognito console. You can set a trigger with the LambdaConfig
parameter in a CreateUserPool
or UpdateUserPool
API request. Or you can also use the below command for it:
aws cognito-idp update-user-pool --user-pool-id {user_pool_id} --lambda-config "CustomEmailSender={LambdaVersion=V1_0,LambdaArn={lambda-arn} },KMSKeyID={key-arn}"
To verify if your triggers are configured correctly, refer to the user pool properties tab of your Cognito user pool in the AWS console.
Recommended settings
We’re almost there. You may encounter some difficulties where the trigger does not work even if all the above steps are correct. Below are some tips related to the Cognito use pool settings in the AWS console:
If you’re using this trigger for the sign-up process, it is recommended to enable the ‘Allow Cognito to automatically send messages to verify and confirm
’ flag of the user pool. The flag is in the ‘Attribute verification and user account confirmation’ section of the ‘Sign-up experience’ tab.
Before running the command to set the trigger, you should disable the ‘Verifying attribute changes
’ flag. If the flag is enabled, you may get theInvalidParameterException.
To fix this issue, you can include its parameter — auto-verified-attributes=”<attribute_name>”
in the command.
Summary
AWS Cognito provides you with the Custom Email Sender Lambda trigger to customize the authentication journey of the user. Using this functionality, you can use a third-party provider or custom methods to send an email from the lambda function. In the trigger configuration, the KMS encryption key is provided along with the lambda function. AWS uses the key to encrypt the authorization code or temporary passwords. They can be decrypted using AWS SDK and passed to the users. You can identify the source of the trigger from the parameter passed to the lambda function and use it in the code.
References:
- AWS documentation on Custom sender Lambda triggers
- AWS documentation on Custom email sender Lambda triggers
- Blog — Custom email configuration for AWS Cognito