Search code examples
amazon-cognito

Error: Authentication result expected (custom flow)


I'm attempting to implement OTP authentication using AWS Cognito. Here's the flow of the authentication:

  1. The user provides their phone number.
  2. AWS sends a verification code to the user's phone number.
  3. The user enters the verification code.
  4. Authentication is completed. Done.

I followed the AWS documentation and configured three AWS Cognito triggers: defineAuthChallenge, createAuthChallenge, verifyAuthChallengeResponse.

Everything works okay. However, if the user enters the verification code incorrectly for the first time and then sends the correct code, the verifyAuthChallengeResponse seems to "cache" the incorrect code result and constantly fails. I also tried to follow the community guidelines, which suggest returning the following response from the defineAuthChallenge upon a failed attempt:

async function defineAuthChallengeLambda(event) {
  if (event.request.session.length === 0) {
    // [CASE-1] If no session, it means the user is authenticating for the first time
    event.response.failAuthentication = false;
    event.response.issueTokens = false;
    event.response.challengeName = "CUSTOM_CHALLENGE";
  } else if (event.request.session.length === 1) {
    if (event.request.session[0].challengeResult === true) {
      // [CASE-2] If the user answered correctly -> authenticated
      event.response.failAuthentication = false;
      event.response.issueTokens = true;
    } else {
      // [CASE-3] If the user didn't answer correctly -> repeat the flow again (!!!)
      event.response.challengeName = "CUSTOM_CHALLENGE";
      event.response.failAuthentication = false;
      event.response.issueTokens = false;
    }
  }
  return event;
}

The [CASE-3] is proposed by the community, but whenever this case happens, my command which triggers the second attempt of the authentication fails with an error (see code below):

import { RespondToAuthChallengeCommand } from "@aws-sdk/client-cognito-identity-provider"

const command = new RespondToAuthChallengeCommand({
  ClientId: envs.IL_USER_POOL_CLIENT_ID,
  ChallengeName: "CUSTOM_CHALLENGE",
  ChallengeResponses: {
    USERNAME: bag.phoneNumber,
    ANSWER: bag.code
  },
  Session: bag.session,
})

await new CognitoIdentityProvider().send(command) // Error: Authentication result expected

It seems that the second try expects either event.response.failAuthentication = true or event.response.issueTokens = true, but neither of those cases is valid for the second retry.

Do you know what I'm doing wrong?"


Solution

  • I must confess that I made a mistake in my logic, and the errors that were appearing were due to a custom error I had defined. However, I also found a solution for it.

    Whenever I call RespondToAuthChallengeCommand, the result of this command includes a session property in case code verification fails. Therefore, I had to take this returned string and pass it again to the next request. After doing this, the flow started to work as expected. The defineAuthChallenge trigger began to receive more than one session, including failed verifications, allowing me to implement multiple retries.

    In other words, in my previous implementation, I used the Session property for all my code attempts, which was incorrect. Now, I retrieve a new session string each time from the RespondToAuthChallengeCommand whenever it fails and pass it to the next attempt (request).