aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.39k stars 2.11k forks source link

Resend MFA Code API #6676

Open aoloo opened 3 years ago

aoloo commented 3 years ago

Is your feature request related to a problem? Please describe. Our workflow MFA is required in Cognito via (SMS). The user enters the login username and password and is redirected to verify the MFA code page. Now comes the edge case where a user does not receive the MFA code due to network issues or other interference. Therefore we need to provide users with the option to resend an MFA code.

Describe the solution you'd like A method to resend MFA Code due to some edge case a user does not receive a code within the initial sign In flow. A similar hook to Auth.resendSignUp() but for MFA Code.

Describe alternatives you've considered Calling the Auth.SignIn() to resend MFA Code is not ideal because signIn requires a username and password.

elorzafe commented 3 years ago

@aoloo

doing Auth.signIn(..) will resend the code, in that case you will need to store in memory the username and password for that purpose.

aoloo commented 3 years ago

@elorzafe @amhinson we are currently implementing that, but the authentication code does not always get sent. There some instances where calling Auth.signIn() does not work.

try {
  const user = await Auth.signIn(username,password);
} catch (err) {
   `Code was not sent successfully!`
 }

This is my current implementation within a on click event when a user clicks a resend-mfa code on a form. It will be really nice to have a resendMFA api call. This can benefit the community implementing MFA.

aoloo commented 3 years ago

@elorzafe Just to note when calling Auth.signIn it returns {"__type":"CodeMismatchException","message":"Invalid code or auth state for the user."}. So it is crucial that we have an api for re sending mfa authentication code.

mitchgillin commented 3 years ago

Seconding! This is an issue for me as well. Would be great if I could resend confirmation codes, without having to make users re-sign in.

pinpointpanda commented 3 years ago

Yeah, also seeing this. We'll workaround with posting to Auth.logIn again, but it does feel like there ought to be an api method for this - it's the only part of the sign up/sign in/reset password etc... workflows that doesn't have a re-send.

cezarcarvalhaes commented 3 years ago

This has been an issue for us for quite some time. I don't like having to hold on to a password in order to call Auth.signIn again for this feature, and asking users to sign in again is really clunky.

aoloo commented 3 years ago

@harrysolovay @elorzafe any movement on this?

MaxwellOldshein commented 3 years ago

Has anyone heard any update on this issue?

martinlanglois commented 3 years ago

Just want to add my name to the list of people who would need this feature. I am not using the Amplify framework though. Only the php SDK. But it's visibly kind of all the same !

chaawlaapooja commented 3 years ago

Just want to add my name to the list of people who require this feature. This is a blocker for my project.

Thomsen-c commented 3 years ago

This is a blocker on one of my projects as well.

pedrohff360 commented 2 years ago

Same here... there's some update?

justinslalom commented 2 years ago

+1, this is a needed feature

sfratini commented 2 years ago

+1 This is very basic feature request at this point. Specially since we would like to send a code to actually validate the MFA before actually enabling it, to confirm the user has access to the phone/email. AWS enabled it right away, without validating anything. And it is funny, since AWS actually ask you for TWO codes before enabling.

tigrenok00 commented 2 years ago

+1

eugendorin commented 2 years ago

+1

jwelfare commented 2 years ago

+1

44mkashif commented 2 years ago

Any update on this issue? This is a blocker on one of my projects as well.

AugustDev commented 2 years ago

Need update on this

Levisnkyyyy commented 2 years ago

Seeking update as well

madlerpar commented 2 years ago

Is there any update on this? The given "workaround" of using Auth.SignIn() does not seem to actually work.

Muzammil98 commented 1 year ago

+1, this is a needed feature

JJ810 commented 1 year ago

If anyone is still looking for this solution here is my workaround/solution.

So to resend OTP code you should do Auth.signIn(email, password) again and update the user object with new response and do Auth.confirmSignIn(user, otp, user.challengename) with updated user object.

Here is my code:

...
const [user, setUser] = useState()
...
 const handleSubmitMfa = async () => {
    if (user) {
      if (user.challengeName === 'SMS_MFA' || user.challengeName === 'SOFTWARE_TOKEN_MFA') {
        try {
          await Auth.confirmSignIn(user, otp, user.challengeName)
          router.push('/')
        } catch (err: any) {
          if (err.code === 'CodeMismatchException') {
            setError('Invalid OTP Code')
          }
        }
      } else if (user.challengeName === 'MFA_SETUP') {
        Auth.setupTOTP(user)
      }
    }
  }

  const handleResend = async () => {
    if (user && user.challengeName === 'SMS_MFA') {
      const userRes = await Auth.signIn(values.email, values.password)
      // Update user object to confirm sign in with newly received code.
      setUser(userRes)
    }
  }

Hope it helps!

LazyAfternoons commented 1 year ago

The solution provided by @JJ810 seems to work just fine (thank you) but we really need this feature.

abdallahshaban557 commented 1 year ago

Hello everyone! Our team is working on introducing this as a feature of our library in a future iteration. We will provide an update on this Github issue when a new version is out. We do not yet have exact timelines, but we will share them once they are known to us!

kceb commented 1 year ago

I too need a solution that does not require me to cache the password... seems pretty insecure. Thankfully I'm doing this server-side. Still would prefer an API that would just resend the code

ovidiu-a commented 1 year ago

+1, this is a needed feature

erinleigh90 commented 1 year ago

Cognito does not currently provide the ability for us to resend the MFA code. Until they provide this functionality, we cannot implement in amplify. We will continue to stress the importance of this issue internally and provide an update as soon as we have one.

abdallahshaban557 commented 1 year ago

Closing this as a duplicate of #2010

aoloo commented 1 year ago

@abdallahshaban557 I would prefer we close #2010 and keep this one open. It is more active and recent. Thanks!

abdallahshaban557 commented 1 year ago

@aoloo - that is true - I see that as well. Done!

abduncan commented 1 year ago

+1

luigi1610 commented 1 year ago

the workaround of @JJ810 is not praticable. We cannot store user password. This problem is present even with aws-sdk module, it seems that cognito miss this essential feature, How is it possible? Today no solution yet.

abdallahshaban557 commented 1 year ago

We are working with the Cognito team to enable this feature soon. Once that feature is available in Cognito, the Amplify team is intending on introducing an API to handle this ASAP. We will provide updates on this GH issue.

jmnProcom commented 1 year ago

Also looking for this feature. But for now, is there a known workaround to trigger an SMS code when SMS is enabled but NOT the preferred method? Signing in the user again would not work in this case.

For instance, a user logging in with "SOFTWARE_TOKEN_MFA" set as preferred method but for some reason that user don't have access to his app and want to use SMS instead.

To be more specific, talking about the following: image

deepaktammali commented 11 months ago

Thanks for the great library.

The work-around being discussed works for username/password login, Is there a way we can resend 2FA code for other providers such as google?

abdallahshaban557 commented 10 months ago

Hello everyone, the Cognito team is collecting feedback since they are planning on enabling this feature. If you are open to having us reach out and get your feedback on our proposed experience, can you please send us an email to aws-amplify-customer@amazon.com with the subject of Resend MFA feedback

ashwinchandran13 commented 7 months ago

I'm receiving the MFA code automatically but on using the SMS MFA codes I'm getting a 'CodeMismatchException: Invalid code or auth state for the user' just as @aoloo described

ashwinchandran13 commented 7 months ago

CodeMismatchException: Invalid code or auth state for the user

A closed issue had a discussion what @aoloo described. Interestingly, the issue was closed without having a solution which rendered the discussion to be locked which lead me to posting the solution here but since anyone who is searching this issue is lead to here, here is the solution:

After receiving the code as SMS, do not trigger/call authenticate flow once again to send the SMS MFA code which causes the code to be invalidated and after getting the error you might notice another SMS MFA code being send which is due to the last authenticate call done to send initial SMS MFA code.

Instead create another path or method in which you can use either adminRespondToAuthChallenge or sendMFACode provided the Session parameter must have a value of session from the last authenticate call.

In my case, I had built REST API's which calls the authenticate function within a Lambda.

authenticate function is called after user submits email & password in frontend.


    import { CognitoUser } from 'amazon-cognito-identity-js';

    // inside authenticate lambda function
    const userData = {
       Username: user.email,
       Pool:     userPool
    };
    const cognitoUser = new CognitoUser(userData);
    cognitoUser.authenticateUser(authenticationDetails, {
      onSuccess: ...,
      onFailure: ...,
      mfaRequired: (challengeName, challengeParameters) => {
        const { Session } = cognitoUser;
        if (payload.mfa === undefined) {
         // returns mfaRequired response to frontend
          resolve({mfaRequired: true, session: Session}) 
        }
      }
   })

sendSMSMFA Lambda function which is called after user enters the code into the frontend

// inside sendSMSMFA function
const cognitoAdminUser = new CognitoIdentityServiceProvider({apiVersion: '2016-04-18'});
cognitoAdminUser.adminRespondToAuthChallenge({
 UserPoolId: user_pool_id,
 ClientId: client_id,
 ChallengeName: 'SMS_MFA',
 Session: payload.session,
 ChallengeResponses: {
   SMS_MFA_CODE: payload.mfaCode,
   USERNAME: payload.email
  },
 }, (err, data) => {
   if (err) {
    console.log('error responding to auth challenge', err);
    reject(err);
   } else {
      console.log('Successfully responded to auth challenge', data);
      const idToken = data.AuthenticationResult.IdToken;
      const AccessToken = data.AuthenticationResult.AccessToken;
      const refreshToken = data.AuthenticationResult.RefreshToken;
      resolve({token: idToken, access: AccessToken, refresh: refreshToken})
    }
   })

For anyone who wonders about why this isn't happening when using TOTP software token mehod is because the MFA code clock is separate of that of the cognito clock and thus there will always be a sync there even if codes are send in different authenticate calls but SMS MFA is really dependent on session id.

117 commented 7 months ago

+1337

felipecrestani commented 6 months ago

??????

valentinbeggi commented 6 months ago

+1

sagenate24 commented 6 months ago

+1

elton-bz commented 6 months ago

+1

fcoradini commented 5 months ago

+1

Sc0ra commented 5 months ago

+1

owhittlef commented 4 months ago

+1... blocker for my project.

I will use the workaround for now, but as others have said, I do not want to cache the user's password.