Reputation: 401
We are trying to implement MultiFactor Authentication using Authenticator App for a custom auth flow using passwordless email authentication. We are currently using the password-less email authentication flow from aws blog "Implementing passwordless email authentication with Amazon Cognito".
We are required to provide MFA to our users using an Authenticator App. but are unable to implement SOFTWARE_TOKEN_MFA on top of this CUSTOM_CHALLENGE.
We have successfully implemented the enabling MFA steps and now MFA is enabled for the user and the preferredMFA is set to "SOFTWARE_TOKEN_MFA". We made few modifications to the code in "Define Auth Challenge" function so that if a user has enabled MFA then upon successfully completing the "CUSTOM_CHALLENGE" the users challengeName is set to "SOFTWARE_TOKEN_MFA".
We were expecting that after the CUSTOM_CHALLENGE is successfully completed and the challengeName is changed to "SOFTWARE_TOKEN_MFA" we can call Auth.confirmSignIn function to validate the code from the authenticator app, but this throws "CodeMismatchException: Invalid code or auth state for the user.". We have throughly checked that code entered is correct so the issue is in the auth state.
Are we doing this right ?
/**
* @type {import('@types/aws-lambda').DefineAuthChallengeTriggerHandler}
*/
const getUserPreferredMFA = require('./functions/getUserPreferredMFA');
//define-challenge
exports.handler = async event => {
try {
console.log("event: ", JSON.stringify(event, null, 2));
}
catch (err) {
console.log("error: ", err);
}
if (event.request.session &&
event.request.session.find(attempt => attempt.challengeName !== 'CUSTOM_CHALLENGE')) {
// We only accept custom challenges; fail auth
event.response.issueTokens = false;
event.response.failAuthentication = true;
}
else if (event.request.session &&
event.request.session.length >= 3 &&
event.request.session.slice(-1)[0].challengeResult === false) {
// The user provided a wrong answer 3 times; fail auth
event.response.issueTokens = false;
event.response.failAuthentication = true;
}
else if (event.request.session &&
event.request.session.length &&
event.request.session.slice(-1)[0].challengeName === 'CUSTOM_CHALLENGE' && // Doubly stitched, holds better
event.request.session.slice(-1)[0].challengeResult === true) {
//check if user has enabled MFA by checking preferredMFA is "SOFTWARE_TOKEN_MFA"
if (await getUserPreferredMFA(event.userPoolId, event.userName) === "SOFTWARE_TOKEN_MFA") {
event.response.challengeName = 'SOFTWARE_TOKEN_MFA';
event.response.issueTokens = false;
event.response.failAuthentication = false;
}
else {
event.response.issueTokens = true;
event.response.failAuthentication = false;
}
}
else {
// The user did not provide a correct answer yet; present challenge
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
}
return event;
};
The code for CreateAuthChallenge and Verify AuthChallenge is same as in the AWS Blog.
{
"challengeName": "CUSTOM_CHALLENGE",
"challengeParam": {
"USERNAME": "-------------------",
"email": "[email protected]"
},
"signInUserSession": null,
"authenticationFlowType": "CUSTOM_AUTH"
....
}
{
"challengeName": "SOFTWARE_TOKEN_MFA",
"challengeParam": {
"USERNAME": "-------------------",
"email": "[email protected]"
},
"signInUserSession": null,
"authenticationFlowType": "CUSTOM_AUTH" .....
}
Upvotes: 1
Views: 233