amplify-js: user.sendCustomChallengeAnswer is not a function

This is a long article but organized pretty neat. Please read it and help me if you have any clue. It’s easy to reproduce using simple express application. (just separate Auth.signIn and Auth.sendCustomChallengeAnswer in different router)

Notice

Similar symptom found in old issue(#1896), but it seems to be happening in frontend, while I’m having it in backend.

=======

Which Category is your question related to? : Usage Question

What AWS Services are you utilizing? Cognito with Amplify Auth

Provide additional details e.g. code snippets

Current situation

  1. I’m implementing Auth.signIn in express based Node.js REST API server. (Please note that this is backend application, not frontend such as react or angular).

  2. So far, I’ve successfully implemented Auth.signUp, Auth.confirmSignUp and Auth.signIn.

  3. For custom MFA (sending verification code to user’s email), I’m using CUSTOM_AUTH and my lambda functions bound to Cognito user pool are successfully triggered.

  4. Currently implemented features(Auth.signUp, Auth.confirmSignUp and Auth.signIn) were implemented in separated endpoints(i.e., those Auth methods are called by different REST APIs), so as Auth.sendCustomChallengeAnswer that I’m having trouble with.

Problem

  1. As I separated Auth.signIn and Auth.sendCustomChallengeAnswer (due to the separation of endpoints, “/login” and “/verification/login”, respectively), user object returned by Auth.signIn is no longer available to pass to Auth.sendCustomChallengeAnswer.

Trial 1

  1. Here’s the login code snippet I’m using now:
        // This is a method of Authentication Helper that "/login" endpoint calls.
        // "/login" endpoint is express router which receives email and password from clients.
	login(username, password, resolve, reject) {
		Auth.signIn(username, password)
		.then(user => {
			if (user.challengeName === "CUSTOM_CHALLENGE") {
                                // Here, I tried to pass user object and save it in express-session.
                                // However, when I retrieve the user object from express-session in other api (/verification/login),
                                // the retrieved user object doesn't have sendCustomChallengeAnswer method.
				resolve(user)
			} else {
				reject()
			}
		})
		.catch(error => {
			// Handling error...
		})
	}
  1. Here, passing user object and putting it in express-session doesn’t work as described in the comment above. This is the failed code snippet of login verification:
        // This is a method of Authentication Helper that "/verification/login" endpoint calls.
        // argument "user" is retrieved from express-session and passed by "/verification/login" router.
	verifyLoginTrial(user, code, resolve, reject) {
		Auth.sendCustomChallengeAnswer(user, code)
		.then(signedUser => {
			console.log(signedUser)
			resolve(signedUser)
		})
		.catch(error => {
                        // Handling error...
		})
	}
  1. Using this code, I got this error
user.sendCustomChallengeAnswer is not a function

Trial 2

  1. Same code for login

  2. This time, I’ve tried manually creating CognitoUser but it also didn’t work.

...
const CognitoUser = require("amazon-cognito-identity-js").CognitoUser
...
// Start of Authentication Helper
        constructor() {
                // Calling Amplify.configure()
                ...
		this.userPool = new CognitoUserPool({ 
			UserPoolId: poolData.UserPoolId,
			ClientId: poolData.ClientId
		})
        }

        ...

        // Here, instead of saving user object in express-session,
        // I saved username and user.Session in express-session to manually create CognitoUser,
        // which is directly imported from "amazon-cognito-identity-js" library
	verifyLoginTrial(session, username, code, resolve, reject) {
		// Manually create cognito user
		const user = new CognitoUser({
			Username: username, 
			Pool: this.userPool
		})
		user.authenticationFlowType = "CUSTOM_AUTH"
		user.Session = session

		// Send verification code
		Auth.sendCustomChallengeAnswer(user, code)
		.then(signedUser => {
			console.log(signedUser)
			resolve(signedUser)
		})
		.catch(error => {
                        // Handling error...
		})
	}
  1. Using this code, I got this error
AuthClass - Failed to get the signed in user No current user

Question

  1. How can I safely separate Auth.signIn and Auth.sendCustomChallengeAnswer?
  2. or more specifically, How can I safely pass user object returned by Auth.signIn to Auth.sendCustomChallengeAnswer in other API?
  3. if there’s no solution to question 2, then how can I call Auth.sendCustomChallengeAnswer with manually created CognitoUser without getting “No current user” error?

Thank you for reading this long question.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 4
  • Comments: 17 (4 by maintainers)

Most upvoted comments

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Our requirement was also the same and we managed to get the customAuth flow working by creating cognitoUserPool and cognitoUser instance from localStorage/sessionStorage before calling sendCustomChallengeAnswer.

Example:

const userPoolData = {
  Attributes: values(from localStorage);
}
const cognitoUserPool = new CognitoUserPool(userPoolData);

const userData = {
  Attributes: values(from localStorage);
}
const cognitoUser = new CognitoUser(userData);

Auth.sendCustomChallengeAnswer(cognitoUser, validationCode);