Incorrect documentation for post-login action event object

According to this page, the authentication object contains a methods array that should have objects with "name": "mfa" if the user completed MFA during login. These objects are never present in the array when received by the post-login action.

Is it possible to determine if the user performed MFA during login? I need this information added to the access token, I can’t use anything from the ID token.

event.authentication

(Optional) Details about authentication signals obtained during the login flow.

Includes the following properties:

  • methods Array of objects.Contains the authentication methods a user has completed during their session.Array elements:
  • One of the following object schemas:
    • An object with the following properties:
      • name String.The name of the first factor that was completed. Values include the following:
        • "federated" A social or enterprise connection was used to authenticate the user as the first factor.
        • "pwd" A password was used to authenticate a database connection user as the first factor.
        • "passkey" A passkey was used to authenticate a database connnection user as the first factor.
        • "sms" A Passwordless SMS connection was used to authenticate the user as the first factor.
        • "email" A Passwordless Email connection was used to authenticate the user as the first factor or verify email for password reset.
        • "phone_number" A phone number was used for password reset.
        • "mock" Used for internal testing.
        • string A custom authentication method denoted by a URL (as second or later factor).
      • timestamp String.
    • An object with the following properties:
      • name The value “mfa”. The user completed multi-factor authentication (second or later factors).
      • timestamp String.

Hi Taylor,
Regular MFA flow is happening after post-login flow. It is a separate flow, that is why you are unable to see “mfa” string in the “methods” array.
If you’re going to use challengeWith or challengeWithAny functions, the MFA is happening in the “middle” of the post-login flow and should add to the array the “mfa” string after it ends.

In the end of Customize MFA Selection for Universal Login - How it works there is a mention about the array “methods”.

For your second question - You can challenge the user with the functions I mentioned above and if the user succeeds the challenge the action will continue, else it fails. I think that is the best determination that you could have.

Hope I helped!

Thanks for the info. I don’t need to challenge the user for MFA, I need information about the authentication flow that should have already completed.

I had found this other forum post that uses the authentication methods to determine if MFA had been performed. I don’t understand how the authentication methods array sometimes contains MFA and sometimes doesn’t. It also seems like the post-login action gets called during silent authentication or when using a refresh token, so it’s pretty confusing how it really works.

Other recommendations I’ve seen suggest using claims from the ID token, but this won’t work for my use case. I need the claim added to the access token and there doesn’t appear to be any other place aside from the post-login action that lets you add claims to the access token.

It’s a bit misleading to call it a post-login action if it’s actually running in the middle of the authentication flow and you can’t see whether or not MFA was completed.

Yes, there are some problems with the regular flow (that doesn’t include challenging the user).
To solve that, I think they added the challenging option.

As what I think is the solution for your situation is to change the MFA to be challenged manually from the code (as I mentioned how above) and get more power and control on your flow.
You will be able to know all the relevant data on the user MFA flow.

A simple logic also could be that if the user have enrolled factors you know for sure that he will be challenged (Only if your enforcing MFA if user have MFA). so as simple as it can get:

let enrolledFactors = event.user.enrolledFactors?.map((factor) => factor.type) || [];

    if ( enrolledFactors.length > 0 ){

        // If we managed to get here, we for sure have  MFA factors and we will be challenged
        // Now lets add to the idToken that the user has finished MFA (before it happens)
        api.idToken.setCustomClaim("mfa_completed", true);
    }

For example of MFA enforcement :

    let enrolledFactors = event.user.enrolledFactors?.map((factor) => factor.type) || [];

    if ( enrolledFactors.length === 0 ){
        api.authentication.enrollWith(
            {type: 'otp'},
            {
                additionalFactors :[{type: 'phone', options: {preferredMethod: 'both'}}]
            }
        );
    } else {
       api.authentication.challengeWith(
           {type: 'otp'},
           {
               additionalFactors :[{type: 'phone', options: {preferredMethod: 'both'}}]
           }
       );
    }

    // If we managed to get here, we for sure have finished challenge MFA
    // Now lets add to the idToken that the user has finished MFA
    api.idToken.setCustomClaim("mfa_completed", true);

Or:

    let enrolledFactors = event.user.enrolledFactors?.map((factor) => factor.type) || [];

    if ( enrolledFactors.length > 0 ){
        api.authentication.challengeWith(
            {type: 'otp'},
            {
                additionalFactors :[{type: 'phone', options: {preferredMethod: 'both'}}]
            }
        );

        // If we managed to get here, we for sure have finished challenge MFA
        // Now lets add to the idToken that the user has finished MFA
        api.idToken.setCustomClaim("mfa_completed", true);
    }