Search code examples
amazon-web-servicesamazon-cognitomulti-factor-authentication

UserMFASettingList field of AdminGetUserResponse is empty


I need to determine the MFA configuration for a specific Cognito user via SDK.

My current logic is based on AdminGetUser API and in particular on userMFASettingList and preferredMfaSetting response fields.

As per https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-cognito-identity-provider/modules/admingetuserresponse.html#usermfasettinglist, userMFASettingList is defined as

The MFA options that are activated for the user. The possible values in this list are SMS_MFA and SOFTWARE_TOKEN_MFA.

while mfaOptions is marked as deprecated and its use is discouraged.

I tested a pool with mandatory SMS MFA but userMFASettingList is empty, despite being able to complete the MFA challenge and log in successfully via Cognito Hosted UI.

Empty userMFASettingList

Mandatory MFA on pool settings

Is this a bug? What logic should I use?


Solution

  • Is this a bug?

    Seems like it.

    Unless you call AdminSetUserMFAPreference at least once, UserMFASettingList will always be empty by default in a AdminGetUser call even if MFAOptions is correctly populated.

    This is not returned / empty at an API level, so the SDK doesn't make a difference here.

    1. Create user
    2. Go through setting up MFA
    3. Note that console says 'MFA methods: SMS'
    4. Call AdminGetUser and check that UserMFASettingList is empty while MFAOptions is populated
    5. Call AdminSetUserMFAPreference to 'reassert' the SMS MFA option
    6. Call AdminGetUser again and check that both UserMFASettingList & MFAOptions are now populated, even though you practically didn't change anything
    ➜  ~ aws cognito-idp admin-get-user \
         --region eu-west-1 \
         --user-pool-id xxx \
         --username user1 \
         | jq .
    
    {
      "Username": "user1",
      "UserAttributes": [
        ...
      ],
      "UserCreateDate": "xxx",
      "UserLastModifiedDate": "xxx",
      "Enabled": true,
      "UserStatus": "CONFIRMED",
      "MFAOptions": [
        {
          "DeliveryMedium": "SMS",
          "AttributeName": "phone_number"
        }
      ]
    }
    
    ➜  ~ aws cognito-idp admin-set-user-mfa-preference \
        --user-pool-id xxx \
        --username user1 \
        --sms-mfa-settings Enabled=true
    
    ➜  ~ aws cognito-idp admin-get-user \
         --region eu-west-1 \
         --user-pool-id xxx \
         --username user1 \
         | jq .
    
    {
      "Username": "user1",
      "UserAttributes": [
        ...
      ],
      "UserCreateDate": "xxx",
      "UserLastModifiedDate": "xxx",
      "Enabled": true,
      "UserStatus": "CONFIRMED",
      "MFAOptions": [
        {
          "DeliveryMedium": "SMS",
          "AttributeName": "phone_number"
        }
      ],
      "UserMFASettingList": [
        "SMS_MFA"
      ]
    }
    

    I need to determine the MFA configuration for a specific Cognito user via SDK.

    What logic should I use?

    Sadly, you can't easily do it.

    You need a combination of PreferredMfaSetting & UserMFASettingList to be able to determine the MFA configuration for a user. With the above bug (as far as I can see) fixed, even if UserMFASettingList is populated correctly first time round, that's just a list of available MFA options for the user. It's not what the user has selected.

    There isn't a CurrentMfaSetting field returned by the Cognito API.