Amplify-js: Awkward user experience for `mfaRequired` step after login

Created on 1 Mar 2018  路  19Comments  路  Source: aws-amplify/amplify-js

Do you want to request a feature or report a bug? bug / UX issue

What is the current behavior?

I may be unique in questioning this, or completely implementing this incorrectly, but I find the MFA Required step of the login process really awkward to work with.

When a user signs in and MFA is required, the step requires a popup call from the service itself whilst in the login flow resulting in poor user experience and actually seems like an anti-pattern to me, see Use Case 23 below:

cognitoUser.authenticateUser(authenticationDetails, {
    onSuccess: (result) => {...},
    onFailure: (err) => {...}
    mfaRequired: (codeDeliveryDetails) => {

        // By this point, Cognito has SMS'd the user
        // Since we have access to a CognitoUser object during the login process
        // we have to request the SMS input *here* from the user.
        // The web examples I've seen suggest having a `confirm()` prompt
        // or react-native example I've seen suggest similar prompt libraries
        // for example:

        const mfaCode = prompt('Enter your SMS MFA Code');

        cognitoUser.sendMFACode(
            mfaCode, 
            {
                onSuccess: (result) => {...}
                onFailure: (err) => {...}
            }, 
            'SMS_MFA')
    }
});

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than AWS Amplify.

See above.

What is the expected behavior?

I would love to be able to switch screens to an MFA code input screen and perform the sendMFACode there. I do not have access to a CognitoUser object outside of the login flow since the session is never captured. I think that the confirmRegistration flow is nice but can understand that there may be differences, especially fundamental ones from a security point of view - in short, don't know what the solution could be!

Which versions of Amplify, and which browser / OS are affected by this issue? Did this work in previous versions?

Using [email protected] from npm in both a React-Native and Angular5+ solution, so iOS, Android and Web.

Auth feature-request

All 19 comments

Hi @mrowles, the use case 23 you mentioned is what we expect the behavior, and it is not a bug. We do recommend use a prompt to enter MFA code.

I totally understand your feature request: be able to switch screens to an MFA code input screen and perform the sendMFACode there. I will create this feature request on your behalf and discuss with my teammates. Thanks!

Cheers @yuntuowang - feature request, fair enough :) I鈥檓 more than happy to assist also, I just wanted to confirm that I wasn鈥檛 completely off the mark before diving in. Let me know what what I can do.

Hi @mrowles, sure! Thank you so much for understanding.

@yuntuowang in the meantime, react-native has no prompt functionality for both Android and iOS, any ideas? Custom prompt libraries require a React component to perform, so we'd have to leave the mfaRequired function scope to perform this.

Hi @mrowles,I think you can use Modal to perform the prompt, pretty straightforward. https://facebook.github.io/react-native/docs/modal.html

@yuntuowang But this presents the same problem as using a third party module or building my own - it steps out of the mfaRequired function - which is where we have to capture their input. For example, if we were to do this and go back through the login function flow - you're going to land in a continuous loop of resending new codes.

Hi,
We would also love this feature.

@yuntuowang Hi, is there a status update on this? I would love to help where possible, as it's blocking me from developing in react-native with MFA, so keep me in the loop if you need - although it appears it might be a higher order update in Cognito itself.

@mrowles have you checked out either of the starter apps and how they handle this?
https://github.com/dabit3/react-native-auth-starter is a simpler, newer one, and:
https://github.com/aws-samples/aws-mobile-react-native-starter the larger full blown sample. Both handle mfa, the pet tracker does it with a prompt, and the auth-starter uses a screen I believe for it. Neither of these use the HOCs I believe. But for HOCs. @powerful23 what do you think?

@mlabieniec Thanks for the suggestions.

The first repo frmo dabit3 seems to be deleted/moved (Google still has it indexed and can't find appropriate fork?).

As for the second one, it's interesting. One of my implementations is using react-redux, so slightly different implementation, but I still don't see how this would work as you're stuck in limbo in that commented out section stated above within the login flow. I will test this tonight when I get home but I have a feeling I'll have to rewrite entire auth section using HOCs at this stage, which I was trying to avoid as I don't even know if this will solve the problem.

As for a non-react/flux implementation, you're still having to use a prompt, which I find is a poor experience, both from an implementation standard (UI interference from a service?!) and for the end user.

@mlabieniec @yuntuowang Just noticed that the enhancement tag was removed, does this mean that this is not being considered for work anytime in the near future?

@mlabieniec @richardzcode Hi, any updates here? More than happy to help in any capacity, would love to get this moving as I'm sure I'm not the only one with this issue.

@mrowles can you check this and this which handles the MFA verification process in React?

@powerful23 Thanks for the response.

Amplify didn't really exist/wasn't publicised when I started building, so I've built it all "using [email protected]" - as it was still in it's own repository + was supported.

So let's say I have to rebuild and fix my React Native mobile app using the Amplify code, pain in the butt but fine - this still does not remove the fact that you only have the option of prompt()-ing the user from a service in apps when using the library as it is an anti-pattern mixing UI and services.

@mrowles sorry for the late response. I am not sure if you have tried our withAuthenticator HOC in aws-amplify-react-native which do switch to an MFA code input screen.

The idea to achieve this is:

  1. You have a component which contains all the child components/screens like signIn, signUp, confirmSMS, etc
  2. Every child component has a props called authState and they will render themselves based on this value
  3. When the user signs in:
// in your signIn screen/component: 
cognitoUser.authenticateUser(authenticationDetails, {
    onSuccess: (result) => {...},
    onFailure: (err) => {...}
    mfaRequired: (codeDeliveryDetails) => {
          // this function will change the value of authState so your MFA code input screen get rendered 
          // and the CognitoUser object get passed
          changeState('MFA confirm', CognitoUser)
    }

// in your MFA input screen/component:
const user = this.props.user;
user.sendMFACode();

You can implement it with only amazon-cognito-identity-js if you don't want to use Amplify. For more details or clue you can check the Authenticator. Thanks!

I am not sure if you have tried our withAuthenticator HOC in aws-amplify-react-native

@powerful23 Can I ask that you please read the entirety of the request at hand? I also have an issue with how we have to implement this in a non-react application. It is fundamentally flawed.

Hi @mrowles

I think you can achieve your use case using Amplify. The process would be roughly like this:

  • Call Auth.signIn(username, password)
  • Store the user object returned by it "somewhere" (e.g. a global, a redux store, etc)
  • Call Auth.confirmSignIn(user, code, "SMS_MFA") passing that user
// This global is "somewhere"
let user;
// Store user "somewhere"
user = await Auth.signIn(username, password);
// Read user from "somewhere"
await Auth.confirmSignIn(user, code, "SMS_MFA");

I've prepared a mini app showing how I did this (replace the amplify config with your values if you want to test it against your resources). The overall process happens "in multiple screens", which I think removes the "limbo" part of the equation.

@manueliglesias Thanks buddy, will check it out.

If anyone is coming here late, this issue was not resolved here, but this helpful person over on Stackoverflow came to the rescue with a workaround: https://stackoverflow.com/questions/48801238/flow-for-authentication-when-mfa-required-for-user-in-aws-cognito/51394500#51394500

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cosmosof picture cosmosof  路  3Comments

simon998yang picture simon998yang  路  3Comments

callmekatootie picture callmekatootie  路  3Comments

rygo6 picture rygo6  路  3Comments

shinnapatthesix picture shinnapatthesix  路  3Comments