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:
- Created 5 years ago
- Comments:6
Top GitHub Comments
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:
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:
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:
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):
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.
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.