|
| 1 | +<Callout> |
| 2 | +Note: If you create or update an SMS MFA configuration for your Cognito user pool, the Cognito service will send a test SMS message to an internal number in order to verify your configuration. You will be charged for these test messages by Amazon SNS. |
| 3 | + |
| 4 | +For information about Amazon SNS pricing, see [Worldwide SMS Pricing](https://aws.amazon.com/sns/sms-pricing/). |
| 5 | +</Callout> |
| 6 | + |
| 7 | +MFA (Multi-factor authentication increases security for your app by adding an authentication method and not relying solely on the username (or alias) and password. AWS Amplify uses Amazon Cognito to provide MFA. Please see [Amazon Cognito Developer Guide](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html) for more information about setting up MFA in Amazon Cognito. |
| 8 | + |
| 9 | +Once you enable MFA on Amazon Cognito, you can configure your app to work with MFA. |
| 10 | + |
| 11 | +## Setup TOTP |
| 12 | + |
| 13 | +With TOTP (Time-based One-time Password), your app user is challenged to complete authentication using a time-based one-time (TOTP) password after their username and password have been verified. |
| 14 | + |
| 15 | +You can setup TOTP for a user in your app: |
| 16 | + |
| 17 | +```javascript |
| 18 | +import { Auth } from 'aws-amplify'; |
| 19 | + |
| 20 | +// To setup TOTP, first you need to get a `authorization code` from Amazon Cognito |
| 21 | +// `user` is the current Authenticated user |
| 22 | +Auth.setupTOTP(user).then((code) => { |
| 23 | + // display setup code to user which can be used to manually add an account to Authenticator apps |
| 24 | +}); |
| 25 | + |
| 26 | +// ... |
| 27 | + |
| 28 | +// Then you will have your TOTP account in your TOTP-generating app (like Google Authenticator) |
| 29 | +// Use the generated one-time password to verify the setup |
| 30 | +Auth.verifyTotpToken(user, challengeAnswer) |
| 31 | + .then(() => { |
| 32 | + // don't forget to set TOTP as the preferred MFA method |
| 33 | + Auth.setPreferredMFA(user, 'TOTP'); |
| 34 | + // ... |
| 35 | + }) |
| 36 | + .catch((e) => { |
| 37 | + // Token is not verified |
| 38 | + }); |
| 39 | +``` |
| 40 | + |
| 41 | +## Setup MFA type |
| 42 | + |
| 43 | +Multiple MFA types supported by Amazon Cognito. You can set the preferred method in your code: |
| 44 | + |
| 45 | +```javascript |
| 46 | +import { Auth } from 'aws-amplify'; |
| 47 | + |
| 48 | +// You can select preferred mfa type, for example: |
| 49 | +// Select TOTP as preferred |
| 50 | +Auth.setPreferredMFA(user, 'TOTP') |
| 51 | + .then((data) => { |
| 52 | + console.log(data); |
| 53 | + // ... |
| 54 | + }) |
| 55 | + .catch((e) => {}); |
| 56 | + |
| 57 | +// Select SMS as preferred |
| 58 | +Auth.setPreferredMFA(user, 'SMS'); |
| 59 | + |
| 60 | +// Select no-mfa |
| 61 | +Auth.setPreferredMFA(user, 'NOMFA'); |
| 62 | +``` |
| 63 | + |
| 64 | +## Retrieve current preferred MFA type |
| 65 | + |
| 66 | +You can get current preferred MFA type in your code: |
| 67 | + |
| 68 | +```javascript |
| 69 | +import { Auth } from 'aws-amplify'; |
| 70 | + |
| 71 | +// Will retrieve the current mfa type from cache |
| 72 | +Auth.getPreferredMFA(user, { |
| 73 | + // Optional, by default is false. |
| 74 | + // If set to true, it will get the MFA type from server side instead of from local cache. |
| 75 | + bypassCache: false |
| 76 | +}).then((data) => { |
| 77 | + console.log('Current preferred MFA type is: ' + data); |
| 78 | +}); |
| 79 | +``` |
| 80 | + |
| 81 | +## Advanced use cases |
| 82 | + |
| 83 | +### Sign-in with custom auth challenges |
| 84 | + |
| 85 | +When signing in with user name and password, you will either sign in directly or be asked to pass some challenges before getting authenticated. |
| 86 | + |
| 87 | +The `user` object returned from `Auth.signIn` will contain `challengeName` and `challengeParam` if the user needs to pass those challenges. You can call corresponding functions based on those two parameters. |
| 88 | + |
| 89 | +ChallengeName: |
| 90 | + |
| 91 | +- `SMS_MFA`: The user needs to input the code received from SMS message. You can submit the code by `Auth.confirmSignIn`. |
| 92 | +- `SOFTWARE_TOKEN_MFA`: The user needs to input the OTP(one time password). You can submit the code by `Auth.confirmSignIn`. |
| 93 | +- `NEW_PASSWORD_REQUIRED`: This happens when the user account is created through the Cognito console. The user needs to input the new password and required attributes. You can submit those data by `Auth.completeNewPassword`. |
| 94 | +- `MFA_SETUP`: This happens when the MFA method is TOTP(the one time password) which requires the user to go through some steps to generate those passwords. You can start the setup process by `Auth.setupTOTP`. |
| 95 | + |
| 96 | +The following code is only for demonstration purpose: |
| 97 | + |
| 98 | +```javascript |
| 99 | +import { Auth } from 'aws-amplify'; |
| 100 | + |
| 101 | +async function signIn() { |
| 102 | + try { |
| 103 | + const user = await Auth.signIn(username, password); |
| 104 | + if ( |
| 105 | + user.challengeName === 'SMS_MFA' || |
| 106 | + user.challengeName === 'SOFTWARE_TOKEN_MFA' |
| 107 | + ) { |
| 108 | + // You need to get the code from the UI inputs |
| 109 | + // and then trigger the following function with a button click |
| 110 | + const code = getCodeFromUserInput(); |
| 111 | + // If MFA is enabled, sign-in should be confirmed with the confirmation code |
| 112 | + const loggedUser = await Auth.confirmSignIn( |
| 113 | + user, // Return object from Auth.signIn() |
| 114 | + code, // Confirmation code |
| 115 | + mfaType // MFA Type e.g. SMS_MFA, SOFTWARE_TOKEN_MFA |
| 116 | + ); |
| 117 | + } else if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { |
| 118 | + const { requiredAttributes } = user.challengeParam; // the array of required attributes, e.g ['email', 'phone_number'] |
| 119 | + // You need to get the new password and required attributes from the UI inputs |
| 120 | + // and then trigger the following function with a button click |
| 121 | + // For example, the email and phone_number are required attributes |
| 122 | + const { username, email, phone_number } = getInfoFromUserInput(); |
| 123 | + const loggedUser = await Auth.completeNewPassword( |
| 124 | + user, // the Cognito User Object |
| 125 | + newPassword, // the new password |
| 126 | + // OPTIONAL, the required attributes |
| 127 | + { |
| 128 | + email, |
| 129 | + phone_number |
| 130 | + } |
| 131 | + ); |
| 132 | + } else if (user.challengeName === 'MFA_SETUP') { |
| 133 | + // This happens when the MFA method is TOTP |
| 134 | + // The user needs to setup the TOTP before using it |
| 135 | + // More info please check the Enabling MFA part |
| 136 | + Auth.setupTOTP(user); |
| 137 | + } else { |
| 138 | + // The user directly signs in |
| 139 | + console.log(user); |
| 140 | + } |
| 141 | + } catch (err) { |
| 142 | + if (err.code === 'UserNotConfirmedException') { |
| 143 | + // The error happens if the user didn't finish the confirmation step when signing up |
| 144 | + // In this case you need to resend the code and confirm the user |
| 145 | + // About how to resend the code and confirm the user, please check the signUp part |
| 146 | + } else if (err.code === 'PasswordResetRequiredException') { |
| 147 | + // The error happens when the password is reset in the Cognito console |
| 148 | + // In this case you need to call forgotPassword to reset the password |
| 149 | + // Please check the Forgot Password part. |
| 150 | + } else if (err.code === 'NotAuthorizedException') { |
| 151 | + // The error happens when the incorrect password is provided |
| 152 | + } else if (err.code === 'UserNotFoundException') { |
| 153 | + // The error happens when the supplied username/email does not exist in the Cognito user pool |
| 154 | + } else { |
| 155 | + console.log(err); |
| 156 | + } |
| 157 | + } |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +### Sign-in with custom validation data for Lambda Trigger |
| 162 | + |
| 163 | +You can also pass an object which has the username, password and validationData which is sent to a PreAuthentication Lambda trigger |
| 164 | + |
| 165 | +```js |
| 166 | +try { |
| 167 | + const user = await Auth.signIn({ |
| 168 | + username, // Required, the username |
| 169 | + password, // Optional, the password |
| 170 | + validationData // Optional, an arbitrary key-value pair map which can contain any key and will be passed to your PreAuthentication Lambda trigger as-is. It can be used to implement additional validations around authentication |
| 171 | + }); |
| 172 | + console.log('user is signed in!', user); |
| 173 | +} catch (error) { |
| 174 | + console.log('error signing in:', error); |
| 175 | +} |
| 176 | +``` |
| 177 | + |
| 178 | +### Forcing Email Uniqueness in Cognito User Pools |
| 179 | + |
| 180 | +When your Cognito User Pool sign-in options are set to "_Username_", and "_Also allow sign in with verified email address_", the _signUp()_ method creates a new user account every time it's called, without validating email uniqueness. In this case you will end up having multiple user pool identities and all previously created accounts will have their _email_verified_ attribute changed to _false_. |
| 181 | + |
| 182 | +To enforce Cognito User Pool signups with a unique email, you need to change your User Pool's _Attributes_ setting in [Amazon Cognito console](https://console.aws.amazon.com/cognito) as the following: |
| 183 | + |
| 184 | + |
0 commit comments