question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AWS Cognito optional TOTP MFA error "Unknown error, the response body from fetch is: undefined"

See original GitHub issue

** Which Category is your question related to? ** amazon-cognito-identity-js ** What AWS Services are you utilizing? ** Cognito User Pool ** Provide additional details e.g. code snippets ** I am attempting to get TOTP MFA working with my User Pools. The issue I am running into is that I want to have the MFA set to optional. This is the code that handles the authentication:

const classThis = this;
    cognitoUser.authenticateUser(authenticationDetails, {
      onSuccess: function (result) {
        const accessToken = result.getAccessToken().getJwtToken();
        console.log('Signed in Successfully');
        // here would be the redirection to the internal systems as authentication has been successful at this point
        if (classThis.enableMFA) {
          cognitoUser.associateSoftwareToken(this);
        }
      },

      onFailure: function(err) {
        console.log(err.message);
      },

      mfaSetup: function(challengeName, challengeParameters) {
        cognitoUser.associateSoftwareToken(this);
      },
      // @ts-ignore
      associateSecretCode : function(secretCode) {
        classThis.qrCode = secretCode;
        classThis.showTOTPVerification = true;
        classThis.totpVerify.subscribe(challengeAnswer => {
          console.log('verifying Software Token');
          cognitoUser.verifySoftwareToken(challengeAnswer, 'My TOTP device', this);
        });
      },

      selectMFAType : function(challengeName, challengeParameters) {
        const mfaType = prompt('Please select the MFA method.', ''); // valid values for mfaType is "SMS_MFA", "SOFTWARE_TOKEN_MFA"
        // @ts-ignore
        cognitoUser.sendMFASelectionAnswer(mfaType, this);
      },

      totpRequired : function(secretCode) {
        console.log('mfaRequired');
        classThis.showTOTPVerification = true;
        classThis.totpVerify.subscribe(verificationCode => {
          console.log('sending MFA Token');
          cognitoUser.sendMFACode(verificationCode, this, 'SOFTWARE_TOKEN_MFA');
        });
      },

      mfaRequired: function (codeDeliveryDetails) {
        console.log('mfaRequired');
        classThis.showTOTPVerification = true;
        // const verificationCode = prompt('Please input verification code', '');
        // SOFTWARE_TOKEN_MFA is set here as sendMFACode defaults to SMS MFA by default
        classThis.totpVerify.subscribe(verificationCode => {
          console.log('sending MFA Token');
          cognitoUser.sendMFACode(verificationCode, this, 'SOFTWARE_TOKEN_MFA');
        });
      },
    });
  }

Currently, authentication works perfectly if the MFA is set to required. When set to optional, authentication works but the mfaSetup flag is never triggered. Which is why I added the lines:

if (classThis.enableMFA) {
          cognitoUser.associateSoftwareToken(this);
        }

Within the OnSuccess block. I can trigger the associateSoftwareToken in this but the error I receive is “Unknown error, the response body from fetch is: undefined”. Which indicates to me that I am missing a block within the authenticate User flow. The fetch returned the following key value pair which I think is a hint but have been unable to find much information with it:

ChallengeName: "PASSWORD_VERIFIER"

Has anyone came across this as the documentation is rather limited when it comes to TOTP authentication?

If it was necessary to pass something into the authenticateUser to trigger the mfaSetup that would be awesome. But if I am simply missing a definition then I’d be grateful to be pointed in the right direction.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6

github_iconTop GitHub Comments

1reaction
mattbryce93commented, Oct 3, 2018

So I have managed to get this working and want to update this here to allow anyone else having issues to be able to resolve it.

This would only ever happen to a User Pool where the MFA settings are set to “optional”. Which is fine for me as that is what I want for this use case. With the authenticateUser method called on cognitoUser the onSuccess method within it takes in a result variable. This is fine and is as the docs suggest this should be done. The Docs example is here:

cognitoUser.authenticateUser(authenticationDetails, {
        onSuccess: function (result) {
            // User authentication was successful
        },

Within that onSuccess function I was calling const accessToken = result.getAccessToken().getJwtToken(); Which assumes that the result contains a Token. If it doesn’t it fails.

If a User Pool is optional when they sign in with just a password it will succeed and assign a valid token. Again okay but my code was as follows:

onSuccess: function (result) {
        const accessToken = result.getAccessToken().getJwtToken();
        console.log('Signed in Successfully');
        // here would be the redirection to the internal systems as authentication has been successful at this point
        if (classThis.enableMFA) {
          cognitoUser.associateSoftwareToken(this);
        }
      },

Which will grab the accessToken immediately and if the user selected to set up MFA by ticking a checkbox in my UI to change the boolean ‘enableMFA’. It would then take them to:

associateSecretCode : function(secretCode) {
        classThis.qrCode = secretCode;
        classThis.showTOTPVerification = true;
        classThis.totpVerify.subscribe(challengeAnswer => {
          console.log('verifying Software Token');
          cognitoUser.verifySoftwareToken(challengeAnswer, 'My TOTP device', this);
        });
      },

Which again is behaving as normal. It’s when ‘verifySoftwareToken’ is called that issues arise. It will succeed in verifying the token. But then it will return to the onSuccess method form above and try to get the jwtToken from the result (which doesn’t exist as Cognito does not provide it here as the user is already signed in!). And so it fails at this point and makes it look like the Verification failed. When actually const accessToken = result.getAccessToken().getJwtToken(); is what failed on the second run of it.

Here is my working solution to the problem (although probably not the best or guaranteed to work for every situation):

cognitoUser.authenticateUser(authenticationDetails, {
      onSuccess: function (result) {
        // need to wrap this function to only run if the user is not already logged in
        if (result['accessToken'] != null) {
          const accessToken = result.getAccessToken().getJwtToken();
          if (classThis.enableMFA) {
            cognitoUser.associateSoftwareToken(this);
          }
        } else if (result['Status'] === 'SUCCESS') {
          cognitoUser.getSession(function(err, session) {
            if (err) {
              console.log(err);
              return;
            }
            // console.log('session validity: ' + session.isValid());
            const totpMfaSettings = {
              PreferredMfa : true,
              Enabled : true
            };
            cognitoUser.setUserMfaPreference(null, totpMfaSettings, function(err, result) {
                if (err) {
                  console.log(err);
                }
                console.log('call result ' + result);
            });
          });
          console.log('Setting up MFA');
        }
        // end of wrapper
        console.log('Signed in Successfully');
        // here would be the redirection to the internal systems as authentication has been successful at this point
      },

I’ve simply wrapped everything in some conditionals to check that the result object contains the Keys for each authentication flow. I will update this in the future but for now it has been working as I imagined it should.

0reactions
github-actions[bot]commented, Jun 12, 2021

This issue has been automatically locked since there hasn’t been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.

Read more comments on GitHub >

github_iconTop Results From Across the Web

AWS Cognito user pool signup "Unknown error, the response ...
amazon web services - AWS Cognito user pool signup "Unknown error, the response body from fetch is: undefined" - Stack Overflow. Collectives™ ...
Read more >
Troubleshooting SAML 2.0 federation with AWS
This error can occur if the IAM role specified in the SAML response is misspelled or does not exist. Make sure to use...
Read more >
Managing error responses - Amazon Cognito
Amazon Cognito supports customizing error responses returned by user pools. ... The error response tells you the user name or password is incorrect....
Read more >
Enable TOTP MFA for Amazon Cognito user pools - AWS
Open the Amazon Cognito console. · Choose Manage User Pools. · Choose your app client and select Show details. · Choose Enable username...
Read more >
AWS.CognitoIdentityServiceProvider — AWS SDK for JavaScript
... error occurred else console.log(data); // successful response }); ... If your user pool requires TOTP MFA, Amazon Cognito generates an ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found