AWS Cognito: Custom Challenge with Resend code

0

I have implemented custom MFA with email verification code, its working fine as expected, but now the problem here is i want to implement Resend code button on front end side, when user clicks that i need to generate a new code and that code should be the active one, How can i achieve it? Can we trigger createAuthChallenge directly? As far as i have seen it's not possible

I have tried one approach, which is sending some reserved keyword, based on it will generate a new code and send it to the user, i can get that reserved code in verifyAuthChallenge, how can i pass that to createAuthChallenge? i tried setting in session array in verifyAuthChallenge, but sessions are not available in verify Auth Challenge request object, hence am struck am updating my code below, any help would be appreciated

CreateAuthChallenge code:

exports.handler = async (event) => {
  log.info("event: ", event);
  let verificationCode = "";
  //Only called once after SRP_A and PASSWORD_VERIFIER challenges. Hence session.length == 2
  if (event.request.session.length === 2) {
    verificationCode = await buildCodeAndSendEmail(event);
  } else {
    log.info("Inside else part");
    //if the user makes a mistake, we utilize the verification code from the previous session so that the user can retry.
    const previousChallenge = event.request.session.slice(-1)[0];
    verificationCode = previousChallenge.challengeMetadata;
    if (verificationCode === "Dummyval") {
      verificationCode = await buildCodeAndSendEmail(event);
    }
  }

  //add to privateChallengeParameters. This will be used by verify auth lambda.
  log.info({ verificationCode }, "verficiation code");
  event.response.privateChallengeParameters = {
    verificationCode: verificationCode,
  };

  //add it to session, so its available during the next invocation.
  event.response.challengeMetadata = verificationCode;

  return event;

VerifyAuthChallenge

exports.handler = asyncHandler((event) => {
  log.info("event: ", event);
  let expectedAnswer =
    event.request.privateChallengeParameters["verificationCode"];
  let timePeriod = expectedAnswer.substring(6, expectedAnswer.length);
  console.log({ timePeriod }, "Time period");
  expectedAnswer = expectedAnswer.substring(0, 6);
  const currentTime = new Date().getTime();
  const diff = currentTime - timePeriod;
  const seconds = Math.floor((diff / 1000) % 60);
  const minutes = Math.floor(diff / 1000 / 60);
  event.response.answerCorrect = false;
  log.info(expectedAnswer, seconds, minutes, "expectedAnswer seconds minutes");
  if (event.request.challengeAnswer === expectedAnswer && minutes <= process.env.otpTimeLimit ) {
    event.response.answerCorrect = true;
  }

  //DummyVal is a reserved keyword which ill send from frontend based on this am planning to generate new code 
  if(event.request.challengeAnswer === 'Dummyval') {
    // event.request.session[event.request.session.length-1].challengeMetadata = event.request.challengeAnswer;
  }

  log.info({ event }, "return event");

  return event;
});

Please note i need to generate a new code only if the user clicks that resend button, not on all the cases

1 Answer
-1

In your scenario, you need to regenerate the code when the user clicks the "resend code" button. In order to do this, you might need to make your front-end application initiate a new authentication challenge when this button is clicked. Then, on your back-end side, you should handle this newly initiated challenge by regenerating a new code.

Based on your code, it seems you are already detecting when to generate a new code in the CreateAuthChallenge function.

I noticed that you are using a constant "Dummyval" to detect the "resend" request. However, to make things clearer, I suggest you to use a specific flag that's easier to understand. For example, you could set a variable named resendCode in the client's request when the resend button is clicked, and then check for this variable in your CreateAuthChallenge function.

For instance, on your front-end, you could include the resend flag in your client's request when the "resend code" button is clicked:

Auth.sendCustomChallengeAnswer(cognitoUser, { answer: '', resendCode: true })

And in your CreateAuthChallenge lambda function, you could modify the code as follows:

exports.handler = async (event) => {
  log.info("event: ", event);
  let verificationCode = "";

  const resendCode = event.request.challengeAnswer.resendCode;

  // Regenerate the code if it's the first attempt or if the "resend code" button was clicked.
  if (event.request.session.length === 2 || resendCode) {
    verificationCode = await buildCodeAndSendEmail(event);
  } else {
    // ... The rest of your code
  }
  
  // ... The rest of your code
  return event;
};

Please note that the resendCode flag is set on the client-side and passed with the sendCustomChallengeAnswer call. It is used on the server-side in the CreateAuthChallenge function to decide whether to regenerate the code.

This way, you can have the control to regenerate the code only when the "resend code" button is clicked.

profile picture
answered 9 months ago
  • @Ercan: you will not get the challengeAnswer key on request object in createAuthChallenge lambda, this is the problem i thought about this and also in verifyAuth challenge you will not get the sessions array in request object

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.

Guidelines for Answering Questions