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.41k stars 2.12k forks source link

Cognito incorrectly sends verification sms to phone numbers with leading `0` in area code #13567

Open radoslavzeman opened 1 month ago

radoslavzeman commented 1 month ago

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Authentication

Amplify Version

v6

Amplify Categories

auth

Backend

None

Environment information

``` # Put output below this line System: OS: macOS 13.3.1 CPU: (8) arm64 Apple M1 Pro Memory: 95.55 MB / 16.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 20.11.1 - ~/.volta/tools/image/node/20.11.1/bin/node Yarn: 1.22.18 - ~/.volta/tools/image/yarn/1.22.18/bin/yarn npm: 10.2.4 - ~/.volta/tools/image/node/20.11.1/bin/npm bun: 0.6.3 - ~/.bun/bin/bun Browsers: Chrome: 126.0.6478.127 Safari: 16.4 npmPackages: aws-amplify: ^6.3.8 => 6.3.8 aws-amplify/adapter-core: undefined () aws-amplify/analytics: undefined () aws-amplify/analytics/kinesis: undefined () aws-amplify/analytics/kinesis-firehose: undefined () aws-amplify/analytics/personalize: undefined () aws-amplify/analytics/pinpoint: undefined () aws-amplify/api: undefined () aws-amplify/api/server: undefined () aws-amplify/auth: undefined () aws-amplify/auth/cognito: undefined () aws-amplify/auth/cognito/server: undefined () aws-amplify/auth/enable-oauth-listener: undefined () aws-amplify/auth/server: undefined () aws-amplify/data: undefined () aws-amplify/data/server: undefined () aws-amplify/datastore: undefined () aws-amplify/in-app-messaging: undefined () aws-amplify/in-app-messaging/pinpoint: undefined () aws-amplify/push-notifications: undefined () aws-amplify/push-notifications/pinpoint: undefined () aws-amplify/storage: undefined () aws-amplify/storage/s3: undefined () aws-amplify/storage/s3/server: undefined () aws-amplify/storage/server: undefined () aws-amplify/utils: undefined () crypto-browserify: ^3.12.0 => 3.12.0 inquirer: ^9.2.10 => 9.2.22 npmGlobalPackages: corepack: 0.23.0 npm: 10.2.4 ```

Describe the bug

In signIn(), when MFA is enabled, Cognito sends a verification sms to phone number even if it's in wrong format with leading zero after country code.

Example: Country code: +421 (Slovakia) National phone number format: 09xx xxx xxx International phone number format: +421 9xx xxx xxx - the leading zero is removed from national format

Sometimes, users enter the number with leading zeros as "+421 09xx xxx xxx".

Actual behaviour: We sign-up and sign-in users by phone number in out React Native app. We use static password for sign-up and sign-in and MFA verification SMS as one-time-password for sign-in. The signup/signin flow is roughly as follows:

Even if the users enters wrong number "+421 09xx xxx xxx", the SMS is sent to correct number "+421 9xx xxx xxx", but user is signed in with number "+421 09xx xxx xxx".

This leads to situation, when user is able to sign in into two different accounts (with and without the zero) with the same phone number. Obviously, it happens, and users are confused when they do not see their data (when accidentally signed in with zero).

Expected behavior

Expected behaviour: Cognito should not send a verification SMS to wrongly formatted phone number, instead, it should throw an error in signUp step when user enters the number in wrong format with "leading" zero ("+421 09xx xxx xxx").

Reproduction steps

  1. Install aws-amplify latest version (6.3.8 at this time).
  2. Configure Cognito
    Amplify.configure({
    Auth: {
    Cognito: {
      region: AWS_REGION,
      userPoolId: AWS_USER_POOL_ID,
      userPoolClientId: AWS_USER_POOL_WEB_CLIENT_ID,
    },
    },
    });
  3. Enter any string into STATIC_PASS const.
  4. Enter the phone number in correct format into PHONE const (+421 9xx xxx xxx - any phone number in this format).
  5. Run await signUp({ username: PHONE, password: STATIC_PASS }).
  6. Run await signIn({ username: PHONE, password: STATIC_PASS }).
  7. You should get the SMS with verification code.
  8. Run await confirmSignIn({ challengeResponse: CODE }); where CODE is the verification code you received in SMS.
  9. Run await getCurrentUser() and you should get your user info.

Repeat this with the same phone number but in incorrect format with zero after country code (+421 09xx xxx xxx). You should obtain the SMS on the same phone number, but get completely different user info.

In the code snippet, we use inquirer library to prompt the user to enter the verification code into the console.

This happens in our React Native app but also in this minimal reproduction example provided.

Code Snippet

import inquirer from "inquirer";
import { Amplify } from "aws-amplify";
import { confirmSignIn, getCurrentUser, signIn, signUp } from "aws-amplify/auth";
import { AWS_REGION, AWS_USER_POOL_ID, AWS_USER_POOL_WEB_CLIENT_ID, STATIC_PASS, } from "./constants.mjs";

const PHONE = "+421"; // Enter the phone number here

Amplify.configure({
  Auth: {
    Cognito: {
      region: AWS_REGION,
      userPoolId: AWS_USER_POOL_ID,
      userPoolClientId: AWS_USER_POOL_WEB_CLIENT_ID,
    },
  },
});

const QUESTIONS = [
  {
    type: "input",
    name: "code",
    message: "What's your authentication code?",
  },
];

try {
  const signUpOutput = await signUp({
    username: PHONE,
    password: STATIC_PASS,
  })

  console.log('User registered', signUpOutput)

  await signIn({
    username: PHONE,
    password: STATIC_PASS,
  });

  const { code } = await inquirer.prompt(QUESTIONS);
  await confirmSignIn({ challengeResponse: code });

  console.log('Current user', await getCurrentUser());

} catch (error) {
  console.log(error)
}

package.json:

{
  "name": "amplify-example",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "aws-amplify": "^6.3.8",
    "inquirer": "^9.2.10"
  }
}

Our custom "Pre sign-up Lamba trigger":

export const handler  = async (event) => {
    event.response.autoConfirmUser = true;
    return event;
};

Log output

``` // Put your logs below this line ```

aws-exports.js

No response

Manual configuration

Amplify.configure({
  Auth: {
    Cognito: {
      region: AWS_REGION,
      userPoolId: AWS_USER_POOL_ID,
      userPoolClientId: AWS_USER_POOL_WEB_CLIENT_ID,
    },
  },
});
export const AWS_REGION = "eu-central-1";
export const AWS_USER_POOL_ID = "eu-central-1_pXpE6zBM0";
export const AWS_USER_POOL_WEB_CLIENT_ID = "2f8othmrjillbteieffsknuh1e";

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

cwomack commented 1 month ago

@radoslavzeman, can you clarify in which step of your Auth flow that's using this custom lambda in "Pre sign-up Lambda trigger" that the user enters their phone number? Are you able to share the code of the lambda as well?

It sounds like what is happening is there are two user accounts created within the user pool that differ only by the number used. But just to confirm, you're seeing that texts messages aren't able to be sent to BOTH users (even the one with the improper prefixed "0") for MFA uses?

radoslavzeman commented 1 month ago

Hi @cwomack, I updated the issue description with correct reproduction steps and code snippets.

We use custom lambda in Sign-up > Pre sign-up trigger, as mentioned in issue description and attached in screenshots here in case.

image image

export const handler  = async (event) => {
    event.response.autoConfirmUser = true;
    return event;
};

Also, MFA should be enabled and required in "Sing-in experience".

image

radoslavzeman commented 1 month ago

Regarding this question:

It sounds like what is happening is there are two user accounts created within the user pool that differ only by the number used. But just to confirm, you're seeing that texts messages aren't able to be sent to BOTH users (even the one with the improper prefixed "0") for MFA uses?

Yes, I confirm that there are two user accounts created within the user pool that differ only by the number used.

But the problem is, that even if user signs in with zero or without zero, the MFA text message is sent to the same number (without zero). That means, the user can accidentally create two different accounts, thinking they signed in to the same account (because they receive the verification message in both cases).

The solution is, it should not be allowed to create the account with zero at all. The number with zero is not in valid international format. You even cannot dial the number with zero.

radoslavzeman commented 1 month ago

Hello @cwomack, do you have some news about this issue?