Skip to content

Can not trigger CustomEmailSender_AdminCreateUser event.

0

Although I can catch the forgot password event, I can not catch the admin create user api call event. Is this expected?

  • I can successfully send the confirmation code via email if I execute : aws cognito-idp forgot-password --client-id myClientId --username example@gmail.com
  • The function is not invoked from within the pre signup lambda, which uses the following snippet inside:
    const cognitoIdp = new CognitoIdentityServiceProvider();
    return cognitoIdp.adminCreateUser(params).promise();

Here is my code for the CustomEmailSender. Any help is appreciated.

const base64 = require('base64-js');
const sendgrid = require('@sendgrid/mail');
const encryptionSDK = require('@aws-crypto/client-node');
const { getSecretValue, getParameterValue } = require('./helpers');

const { 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 });


const sendEmail = async (to, code, SendGridAPIKey, locale) => {
  // Other locales should come here.
  let parameterStorePath;
  if (locale === 'he') {
    parameterStorePath = process.env.SENDGRID_FORGOT_PASSWORD_HE_TEMPLATE_ID_PARAMETER_PATH;
  } else {
    parameterStorePath = process.env.SENDGRID_FORGOT_PASSWORD_EN_TEMPLATE_ID_PARAMETER_PATH;
  }

  const templateName = encodeURIComponent(parameterStorePath);
  const templateId = await getParameterValue(templateName);

  const email = {
    to: to,
    from: 'info@bringist.com',
    templateId: templateId,
    dynamicTemplateData: {
      password_reset_link: code,
    },
    subject: 'Cognito Identity Provider registration completed',
  };
  try {
    sendgrid.setApiKey(SendGridAPIKey);
    await sendgrid.send(email);
    console.log(`Email sent to ${to}`);
  } catch (err) {
    console.error(`Error sending email to ${to}: ${err}`);
    throw err;
  }
};


exports.lambdaHandler = async (event) => {
  console.info(`userPoolId: ${event.userPoolId}`)
  console.info(`triggerSource: ${event.triggerSource}`)
  console.info(`event: ${JSON.stringify(event)}`)
  console.info(`request: ${JSON.stringify(event.request)}`)

  if (event.triggerSource === 'CustomEmailSender_ForgotPassword') {
      await handleForgotPassword(event.request)
  } else {
      console.error(`Unsupported triggerSource: ${event.triggerSource}`)
  }

  return event;
};

  const handleForgotPassword = async (request) => {
    const sendGridSecretName = process.env.SENDGRID_API_KEY_SECRET_NAME
    const sendGridApiKey = await getSecretValue(sendGridSecretName);

    // decrypt confirmation code
    let confirmationCode
    if (request.code) {
        const { plaintext } = await decrypt(
            keyring,
            base64.toByteArray(request.code)
        )
        confirmationCode = plaintext
    }
    if (!confirmationCode) {
        console.error('failed to decrypt confirmation code')
        return
    }

    // send email by SendGrid
    await sendEmail(
        request.userAttributes.email,
        Buffer.from(confirmationCode).toString('utf-8'),
        sendGridApiKey,
        request.userAttributes.locale
    )
}
1 Answer
0

To address the issue you're encountering with the adminCreateUser API call not triggering your Lambda function, it is important to understand the behavior of AWS Cognito triggers and the context in which these triggers are executed.

AWS Cognito Triggers

AWS Cognito provides various triggers that can be used to execute custom logic in response to different user pool operations. The CustomEmailSender trigger is designed to handle custom email sending scenarios, but it is only invoked in specific contexts such as password resets or account verification.

Understanding adminCreateUser

The adminCreateUser API call is used to create a new user in the user pool. When you create a user using this API, Cognito sends an invitation message to the user with a temporary password. However, this operation does not directly invoke the CustomEmailSender trigger. Instead, it triggers other Lambda functions if configured, such as the Pre Sign-up, Post Confirmation, or Custom Message triggers.

Custom Message Trigger

To customize the message sent during the adminCreateUser process, you should use the Custom Message trigger. This trigger allows you to customize the email or SMS message that is sent when a user is created via the adminCreateUser API.

Setting Up the Custom Message Trigger

  1. Lambda Function for Custom Message Trigger: Create a Lambda function that handles the custom message logic. Here's an example:
const sendgrid = require('@sendgrid/mail');
const { getSecretValue, getParameterValue } = require('./helpers');

const sendEmail = async (to, code, SendGridAPIKey, locale) => {
  // Other locales should come here.
  let parameterStorePath;
  if (locale === 'he') {
    parameterStorePath = process.env.SENDGRID_FORGOT_PASSWORD_HE_TEMPLATE_ID_PARAMETER_PATH;
  } else {
    parameterStorePath = process.env.SENDGRID_FORGOT_PASSWORD_EN_TEMPLATE_ID_PARAMETER_PATH;
  }

  const templateName = encodeURIComponent(parameterStorePath);
  const templateId = await getParameterValue(templateName);

  const email = {
    to: to,
    from: 'info@bringist.com',
    templateId: templateId,
    dynamicTemplateData: {
      password_reset_link: code,
    },
    subject: 'Cognito Identity Provider registration completed',
  };
  try {
    sendgrid.setApiKey(SendGridAPIKey);
    await sendgrid.send(email);
    console.log(`Email sent to ${to}`);
  } catch (err) {
    console.error(`Error sending email to ${to}: ${err}`);
    throw err;
  }
};

exports.lambdaHandler = async (event) => {
  console.info(`userPoolId: ${event.userPoolId}`);
  console.info(`triggerSource: ${event.triggerSource}`);
  console.info(`event: ${JSON.stringify(event)}`);
  console.info(`request: ${JSON.stringify(event.request)}`);

  if (event.triggerSource === 'CustomMessage_AdminCreateUser') {
    await handleAdminCreateUser(event.request);
  } else if (event.triggerSource === 'CustomEmailSender_ForgotPassword') {
    await handleForgotPassword(event.request);
  } else {
    console.error(`Unsupported triggerSource: ${event.triggerSource}`);
  }

  return event;
};

const handleAdminCreateUser = async (request) => {
  const sendGridSecretName = process.env.SENDGRID_API_KEY_SECRET_NAME;
  const sendGridApiKey = await getSecretValue(sendGridSecretName);

  const userEmail = request.userAttributes.email;
  const temporaryPassword = request.temporaryPassword;

  // send email by SendGrid
  await sendEmail(
    userEmail,
    temporaryPassword,
    sendGridApiKey,
    request.userAttributes.locale
  );
};

const handleForgotPassword = async (request) => {
  const sendGridSecretName = process.env.SENDGRID_API_KEY_SECRET_NAME;
  const sendGridApiKey = await getSecretValue(sendGridSecretName);

  const confirmationCode = request.code;

  // send email by SendGrid
  await sendEmail(
    request.userAttributes.email,
    confirmationCode,
    sendGridApiKey,
    request.userAttributes.locale
  );
};
  1. Attach the Custom Message Trigger: Go to the AWS Cognito console, select your user pool, navigate to Triggers, and attach the Lambda function to the Custom Message trigger.

Verify Configuration

Ensure that your Lambda function has the necessary permissions and the environment variables are correctly set.

You can customize the email or SMS messages sent during the adminCreateUser process. This allows you to send emails using SendGrid or any other email service provider, overcoming the limitations you're experiencing with the CustomEmailSender trigger not being invoked for the adminCreateUser API call.

EXPERT

answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.