Overview
When enabling MFA through a Post-Login Action and utilizing Silent Authentication, the error Failed Silent Authentication - Multifactor Authentication Required is received. This article will explain how to resolve this issue while enabling multiple authentication methods at the same priority level, letting the user choose the authentication method they want to be prompted with.
Applies To
- Extensibility
- Actions
- MultiFactor Authentication (MFA)
Cause
This issue appears because the Post-Login Action created is being executed at every Silent Authentication, and it is checking for MFA even after it is already completed.
Solution
The action should verify if the user has already completed MFA. To let the user choose the authentication method, MFA can be enabled with the function challengeWithAny()
. This function takes an array of objects of format key:value
that should describe the authentication method utilized.
Here is a code snippet for this Post-Login Action:
exports.onExecutePostLogin = async (event, api) => {
//verify if the current event holds authentication methods
if (event.authentication && Array.isArray(event.authentication.methods) && event.user.multifactor?.length) {
//declarations:
const authMethods = event.authentication?.methods || []; //array of authentication methods
const isMFAAuthenticated = !!authMethods.find((method) => method.name === 'mfa'); //boolean that checks if there is the ‘mfa’ method
const isRefreshTokenProtocol = event?.transaction?.protocol === "oauth2-refresh-token"; //boolean that checks if the transaction has refresh token protocol
//check if any of the booleans declared are true and set multifactor to 'none' to avoid getting the error
if (isMFAAuthenticated || isRefreshTokenProtocol) {
api.multifactor.enable('none');
} else if (!isMFAAuthenticated) {
//if booleans are false, set multifactor to 'any'
api.multifactor.enable('any', { allowRememberBrowser: true });
//allow user to choose their desired authentication method with challengeWithAny()
api.authentication.challengeWithAny([{ type: "email" }, { type: "otp" }]);
}
}
}
NOTE: This is an example and should be tested in lower environments first.