MFA Actions Triggered Twice

I’m working on setting up conditional MFA based on a few factors. To start with I was just trying to set based on the last time they had an MFA session.

The issue I am seeing is that when I hit api.authentication.challengeWith or .enrollWith the actions start over again. If I don’t have a break condition it will just loop forever. I have 3 other actions in Post-Login and they all restart. Am I missing something in my MFA api.authentication.challengeWith()?

Code

const mfaSeconds = 60;

exports.onExecutePostLogin = async (event, api) => {
    console.log('MFA Filter - onExecutePostLogin');
    console.log(event.authentication.methods);

    if (event?.user?.email?.startsWith("mytestuser")) {
        if (event != null && event.user != null && event.user.app_metadata != null && event.user.app_metadata["last_mfa"] != null) {
            var timestamp = Math.floor(Date.now() / 1000);
            console.log("timestamp:", timestamp);
            var mfaTimestamp = Number(event.user.app_metadata["last_mfa"]);
            console.log("mfaTimestamp:", mfaTimestamp)
            console.log("mfaTimestamp + mfaSeconds: ", mfaTimestamp + mfaSeconds);
            if ((mfaTimestamp + mfaSeconds) > timestamp) {
                console.log("Skipping MFA check, only " + (mfaTimestamp + mfaSeconds - timestamp) + " seconds since last MFA");
                return event;
            }
        }
    }

    if (event?.user?.email?.startsWith("mytestuser")) {
        console.log('MFA enrollment');
        var enrolledFactors = event.user.enrolledFactors;
        if (enrolledFactors && enrolledFactors.length) {
            console.log("Already enrolled, challenging...");
            let challengeFactors = enrolledFactors.map(m => ({type: m.type}));
            for (let i = 0; i < enrolledFactors.length; i++) {
                console.log("enrolledFactors:" + enrolledFactors[i]);
                console.log("challengeFactors:" + challengeFactors[i]);
            }
            api.authentication.challengeWith({type: 'otp'});
            UpdateLastMFA(event, api);
        } else {
            console.log("No enrollment, enrolling...");
            api.authentication.enrollWith({type: 'otp'}, {type: 'phone'});
            UpdateLastMFA(event, api);
        }
    }
    return event;
};

function UpdateLastMFA(event, api) {
    if (event.user.email.startsWith("mytestuser")) {
        console.log('UpdateLastMFA');
        const FORM_ID = 'ap_heLu3AM1Rd8GDCg6MNdtqG';
        api.prompt.render(FORM_ID);
    }
}

Logs

3:27:15 PM: sandbox runtime ready
3:27:16 PM: Check Reset Password - onExecutePostLogin
3:27:16 PM: finished webtask request
3:27:16 PM: sandbox runtime ready
3:27:16 PM: finished webtask request
3:27:16 PM: sandbox runtime ready
3:27:16 PM: MFA Filter - onExecutePostLogin
3:27:16 PM: [ { name: 'federated', timestamp: '2024-11-01T20:27:15.305Z' } ]
3:27:16 PM: timestamp: 1730492836
mfaTimestamp: 1730492443
mfaTimestamp + mfaSeconds: 1730492503
3:27:16 PM: MFA enrollment
Already enrolled, challenging...
enrolledFactors:[object Object]
3:27:16 PM: challengeFactors:[object Object]
3:27:16 PM: UpdateLastMFA
3:27:16 PM: finished webtask request
3:27:18 PM: sandbox runtime ready
3:27:18 PM: finished webtask request
3:27:19 PM: Check Reset Password - onExecutePostLogin
3:27:19 PM: finished webtask request
3:27:19 PM: sandbox runtime ready
3:27:20 PM: finished webtask request
3:27:20 PM: MFA Filter - onExecutePostLogin
[ { name: 'federated', timestamp: '2024-11-01T20:27:15.305Z' } ]
3:27:20 PM: timestamp: 1730492840
3:27:20 PM: mfaTimestamp: 1730492837
mfaTimestamp + mfaSeconds: 1730492897
Skipping MFA check, only 57 seconds since last MFA
3:27:20 PM: finished webtask request
3:27:20 PM: sandbox runtime ready
3:27:20 PM: Add User Name - onExecutePostLogin
3:27:20 PM: finished webtask request

I worked with support on this issue so I’ll update here. The issue was an exception in the node.js action code. There seems to be a bug (or maybe it’s intentional) where if you hit an exception in the action it just re-runs all the actions again. This can get you stuck in a never ending loop if you have no break condition.

1 Like

Hi @bradyp,

Thanks for sharing your solution here with the rest of the community!