Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gen2: Setup of MFA is not working #13359

Open
3 tasks done
danoshi opened this issue May 10, 2024 · 11 comments
Open
3 tasks done

Gen2: Setup of MFA is not working #13359

danoshi opened this issue May 10, 2024 · 11 comments
Assignees
Labels
Auth Related to Auth components/category question General question

Comments

@danoshi
Copy link

danoshi commented May 10, 2024

Before opening, please confirm:

JavaScript Framework

Next.js

Amplify APIs

Authentication

Amplify Version

v6

Amplify Categories

auth

Backend

Amplify CLI

Environment information

# Put output below this line
  System:
    OS: macOS 12.7.4
    CPU: (8) x64 Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
    Memory: 693.51 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 22.1.0 - /usr/local/bin/node
    npm: 10.7.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 124.0.6367.201
    Safari: 17.4.1
  npmPackages:
    %name%:  0.1.0 
    @ampproject/toolbox-optimizer:  undefined ()
    @aws-amplify/adapter-nextjs: ^1.1.5 => 1.1.5 
    @aws-amplify/adapter-nextjs/api:  undefined ()
    @aws-amplify/adapter-nextjs/data:  undefined ()
    @aws-amplify/backend: ^1.0.1 => 1.0.1 
    @aws-amplify/backend-cli: ^1.0.2 => 1.0.2 
    @aws-sdk/client-dynamodb: ^3.513.0 => 3.568.0 
    @aws-sdk/lib-dynamodb: ^3.513.0 => 3.568.0 
    @babel/core:  undefined ()
    @babel/runtime:  7.22.5 
    @edge-runtime/cookies:  4.1.1 
    @edge-runtime/ponyfill:  2.4.2 
    @edge-runtime/primitives:  4.1.0 
    @hapi/accept:  undefined ()
    @mswjs/interceptors:  undefined ()
    @napi-rs/triples:  undefined ()
    @next/font:  undefined ()
    @opentelemetry/api:  undefined ()
    @radix-ui/react-alert-dialog: ^1.0.5 => 1.0.5 
    @radix-ui/react-checkbox: ^1.0.4 => 1.0.4 
    @radix-ui/react-dialog: ^1.0.5 => 1.0.5 
    @radix-ui/react-dropdown-menu: ^2.0.6 => 2.0.6 
    @radix-ui/react-icons: ^1.3.0 => 1.3.0 
    @radix-ui/react-label: ^2.0.2 => 2.0.2 
    @radix-ui/react-menubar: ^1.0.4 => 1.0.4 
    @radix-ui/react-slot: ^1.0.2 => 1.0.2 
    @radix-ui/react-toast: ^1.1.5 => 1.1.5 
    @tanstack/react-table: ^8.12.0 => 8.16.0 
    @types/node: ^20.11.17 => 20.12.8 
    @types/react: ^18.2.55 => 18.3.1 
    @types/react-dom: ^18.2.19 => 18.3.0 
    @vercel/nft:  undefined ()
    @vercel/og:  0.6.2 
    acorn:  undefined ()
    amphtml-validator:  undefined ()
    anser:  undefined ()
    arg:  undefined ()
    assert:  undefined ()
    async-retry:  undefined ()
    async-sema:  undefined ()
    autoprefixer: ^10.4.17 => 10.4.19 
    aws-amplify: ^6.3.0 => 6.3.0 
    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 ()
    aws-cdk: ^2.141.0 => 2.141.0 
    aws-cdk-lib: ^2.141.0 => 2.141.0 
    babel-packages:  undefined ()
    browserify-zlib:  undefined ()
    browserslist:  undefined ()
    buffer:  undefined ()
    bytes:  undefined ()
    ci-info:  undefined ()
    class-variance-authority: ^0.7.0 => 0.7.0 
    cli-select:  undefined ()
    client-only:  0.0.1 
    clsx: ^2.1.0 => 2.1.1 (2.0.0)
    commander:  undefined ()
    comment-json:  undefined ()
    compression:  undefined ()
    conf:  undefined ()
    constants-browserify:  undefined ()
    constructs: ^10.3.0 => 10.3.0 
    content-disposition:  undefined ()
    content-type:  undefined ()
    cookie:  undefined ()
    cross-spawn:  undefined ()
    crypto-browserify:  undefined ()
    css.escape:  undefined ()
    data-uri-to-buffer:  undefined ()
    debug:  undefined ()
    devalue:  undefined ()
    domain-browser:  undefined ()
    edge-runtime:  undefined ()
    esbuild: ^0.21.1 => 0.21.1 (0.20.2)
    eslint: ^8.56.0 => 8.57.0 
    eslint-config-next: 14.1.0 => 14.1.0 
    events:  undefined ()
    find-cache-dir:  undefined ()
    find-up:  undefined ()
    fresh:  undefined ()
    geist: ^1.2.2 => 1.3.0 
    get-orientation:  undefined ()
    glob:  undefined ()
    gzip-size:  undefined ()
    http-proxy:  undefined ()
    http-proxy-agent:  undefined ()
    https-browserify:  undefined ()
    https-proxy-agent:  undefined ()
    icss-utils:  undefined ()
    ignore-loader:  undefined ()
    image-size:  undefined ()
    is-animated:  undefined ()
    is-docker:  undefined ()
    is-wsl:  undefined ()
    jest-worker:  undefined ()
    json5:  undefined ()
    jsonwebtoken:  undefined ()
    loader-runner:  undefined ()
    loader-utils:  undefined ()
    lodash.curry:  undefined ()
    lru-cache:  undefined ()
    lucide-react: ^0.330.0 => 0.330.0 
    mini-css-extract-plugin:  undefined ()
    nanoid:  undefined ()
    native-url:  undefined ()
    neo-async:  undefined ()
    next: ^14.2.3 => 14.2.3 
    next-intl: ^3.7.0 => 3.12.1 
    next-qrcode: ^2.5.1 => 2.5.1 
    next-themes: ^0.2.1 => 0.2.1 
    node-fetch:  undefined ()
    node-html-parser:  undefined ()
    ora:  undefined ()
    os-browserify:  undefined ()
    p-limit:  undefined ()
    path-browserify:  undefined ()
    picomatch:  undefined ()
    platform:  undefined ()
    postcss: ^8.4.35 => 8.4.38 (8.4.31)
    postcss-flexbugs-fixes:  undefined ()
    postcss-modules-extract-imports:  undefined ()
    postcss-modules-local-by-default:  undefined ()
    postcss-modules-scope:  undefined ()
    postcss-modules-values:  undefined ()
    postcss-preset-env:  undefined ()
    postcss-safe-parser:  undefined ()
    postcss-scss:  undefined ()
    postcss-value-parser:  undefined ()
    process:  undefined ()
    punycode:  undefined ()
    querystring-es3:  undefined ()
    raw-body:  undefined ()
    react: 18.2.0 => 18.2.0 
    react-builtin:  undefined ()
    react-dom: 18.2.0 => 18.2.0 
    react-dom-builtin:  undefined ()
    react-dom-experimental-builtin:  undefined ()
    react-experimental-builtin:  undefined ()
    react-is:  18.2.0 
    react-refresh:  0.12.0 
    react-server-dom-turbopack-builtin:  undefined ()
    react-server-dom-turbopack-experimental-builtin:  undefined ()
    react-server-dom-webpack-builtin:  undefined ()
    react-server-dom-webpack-experimental-builtin:  undefined ()
    regenerator-runtime:  0.13.4 
    sass-loader:  undefined ()
    scheduler-builtin:  undefined ()
    scheduler-experimental-builtin:  undefined ()
    schema-utils:  undefined ()
    semver:  undefined ()
    send:  undefined ()
    server-only:  0.0.1 
    setimmediate:  undefined ()
    shell-quote:  undefined ()
    source-map:  undefined ()
    source-map08:  undefined ()
    stacktrace-parser:  undefined ()
    stream-browserify:  undefined ()
    stream-http:  undefined ()
    string-hash:  undefined ()
    string_decoder:  undefined ()
    strip-ansi:  undefined ()
    superstruct:  undefined ()
    tailwind-merge: ^2.2.1 => 2.3.0 
    tailwindcss: ^3.4.1 => 3.4.3 
    tailwindcss-animate: ^1.0.7 => 1.0.7 
    tar:  undefined ()
    terser:  undefined ()
    text-table:  undefined ()
    timers-browserify:  undefined ()
    tsx: ^4.9.3 => 4.9.3 
    tty-browserify:  undefined ()
    typescript: ^5.4.5 => 5.4.5 (4.4.4, 4.9.5)
    ua-parser-js:  undefined ()
    unistore:  undefined ()
    util:  undefined ()
    vm-browserify:  undefined ()
    watchpack:  undefined ()
    web-vitals:  undefined ()
    webpack:  undefined ()
    webpack-sources:  undefined ()
    ws:  undefined ()
    zod: ^3.23.7 => 3.23.7 (3.22.4, )
  npmGlobalPackages:
    @aws-amplify/cli: 12.11.1
    npm: 10.7.0
    svgo: 3.0.2
    ts-node: 10.9.2

Describe the bug

My current use case is as follows: I manually create users in the Cognito pool, so I only use the signIn function. When a user receives their credentials via email, they will go to the page and attempt to log in for the first time. After the first login, they will be redirected to the change password page because it is mandatory. I receive the flag "CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED", and the password change works fine when executing the following two lines.

        const challengeResponse = newPassword;
        const result = await confirmSignIn({
          challengeResponse,
        });

Now, my user has the following flag: 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP'. What is currently happening is that I create the QR code with the URL, scan it with my phone, but when I enter the code and submit it, I receive a 'Code Mismatch' error in the console.

Here is the code

        const totpSetupDetails = nextStep.totpSetupDetails;
        const appName = 'my_app_name';
        const setupUri = totpSetupDetails.getSetupUri(appName);
        console.log(setupUri);
        setsetupUri(setupUri.href);
        const challengeResponse = otpCode;
        const result = await confirmSignIn({
          challengeResponse,
        });

I logged the setupUri object and what I see is that the username field is empty. So, my assumption is that it couldn't bind the MFA code with the user.

Here is the output of the log:

URL { href: "otpauth://totp/my_app_name:some_uuid?secret=some_secret&issuer=my_app_name", origin: "null", protocol: "otpauth:", username: "", password: "", host: "", hostname: "", port: "", pathname: "//totp/my_app_name:some_uuid", search: "?secret=some_secret&issuer=my_app_name" }

Here as well, the output after the successful challenge response when I changed the password:

Object { isSignedIn: false, nextStep: {…} }
isSignedIn: false
nextStep: Object { signInStep: "CONTINUE_SIGN_IN_WITH_TOTP_SETUP", totpSetupDetails: {…} }
signInStep: "CONTINUE_SIGN_IN_WITH_TOTP_SETUP"
totpSetupDetails: Object { sharedSecret: "some_secret", getSetupUri: getSetupUri(appName, accountName)
 }
getSetupUri: function getSetupUri(appName, accountName)
sharedSecret: "some_secret"

Expected behavior

The MFA token matches, and the user successfully finishes the setup process.

Reproduction steps

In the describe the bug section I entered the code snippets.

Code Snippet

// Put your code below this line.
import { signIn, confirmSignIn, signOut } from 'aws-amplify/auth';
import { Amplify } from 'aws-amplify';
import outputs from '../../../../amplify_outputs.json';
Amplify.configure(outputs);

export default function Login() {
  // QR code
  const { Canvas } = useQRCode();
  // login
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  // change password
  const [newPassword, setNewPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  // mfa setup
  const [showMFASetup, setShowMFASetup] = useState(false);
  const [showMFAVerify, setShowMFAVerify] = useState(false);
  const [otpCode, setOtpCode] = useState('');
  const [setupUri, setsetupUri] = useState('');

  const [error, setError] = useState('');
  const [showChangePassword, setShowChangePassword] = useState(false);
  const router = useRouter();
  
  const handleSignIn = async (event: any) => {
    event.preventDefault();
    try {
      const output = await signIn({ username, password });
      console.log(output);
      const { isSignedIn, nextStep } = output;
      //const { isSignedIn, nextStep } = await signIn({ username, password });

      if (
        nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED'
      ) {
        setShowChangePassword(true);
        if (newPassword !== confirmPassword) {
          alert('Passwords do not match!');
          return;
        }
        const challengeResponse = newPassword;
        const result = await confirmSignIn({
          challengeResponse,
        });
        console.log(result);
      } else if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP') {
        setShowMFASetup(true);
        const totpSetupDetails = nextStep.totpSetupDetails;
        const appName = 'my_app_name';
        const setupUri = totpSetupDetails.getSetupUri(appName);
        console.log(setupUri);
        setsetupUri(setupUri.href);
        const challengeResponse = otpCode;
        const result = await confirmSignIn({
          challengeResponse,
        });
        console.log(result);
      } else if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_TOTP_CODE') {
        setShowMFAVerify(true);
        const resultmfa = await confirmSignIn({
          challengeResponse: otpCode,
        });
        console.log(resultmfa);
      } else if (nextStep.signInStep === 'DONE') {
        router.push('/summary');
      }
    } catch (error: any) {
      console.error(error.message);
    }
  };

Log output

// Put your logs below this line


aws-exports.js

{
  "auth": {
    "user_pool_id": "user-pool-id-xxx",
    "aws_region": "region-xxxx",
    "user_pool_client_id": "clientid-xxxxx",
    "identity_pool_id": "identity-pool-xxxx",
    "mfa_methods": [
      "TOTP"
    ],
    "standard_required_attributes": [
      "email"
    ],
    "username_attributes": [
      "email"
    ],
    "user_verification_types": [
      "email"
    ],
    "mfa_configuration": "ON",
    "password_policy": {
      "min_length": 8,
      "require_numbers": true,
      "require_lowercase": true,
      "require_uppercase": true,
      "require_symbols": true
    },
    "unauthenticated_identities_enabled": true
  },
  "data": {
    "url": "https://some-url/graphql",
    "aws_region": "eu-central-1",
    "default_authorization_type": "AWS_IAM",
    "authorization_types": [
      "AMAZON_COGNITO_USER_POOLS"
    ],
    "model_introspection": {
      "version": 1,
      "models": {
        "Todo": {
          "name": "Todo",
          "fields": {
            "id": {
              "name": "id",
              "isArray": false,
              "type": "ID",
              "isRequired": true,
              "attributes": []
            },
            "content": {
              "name": "content",
              "isArray": false,
              "type": "String",
              "isRequired": false,
              "attributes": []
            },
            "createdAt": {
              "name": "createdAt",
              "isArray": false,
              "type": "AWSDateTime",
              "isRequired": false,
              "attributes": [],
              "isReadOnly": true
            },
            "updatedAt": {
              "name": "updatedAt",
              "isArray": false,
              "type": "AWSDateTime",
              "isRequired": false,
              "attributes": [],
              "isReadOnly": true
            }
          },
          "syncable": true,
          "pluralName": "Todos",
          "attributes": [
            {
              "type": "model",
              "properties": {}
            },
            {
              "type": "auth",
              "properties": {
                "rules": [
                  {
                    "allow": "public",
                    "provider": "iam",
                    "operations": [
                      "create",
                      "update",
                      "delete",
                      "read"
                    ]
                  }
                ]
              }
            }
          ],
          "primaryKeyInfo": {
            "isCustomPrimaryKey": false,
            "primaryKeyFieldName": "id",
            "sortKeyFieldNames": []
          }
        }
      },
      "enums": {},
      "nonModels": {}
    }
  },
  "version": "1"
}

Manual configuration

No response

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

@danoshi danoshi added the pending-triage Issue is pending triage label May 10, 2024
@cwomack cwomack self-assigned this May 10, 2024
@danoshi
Copy link
Author

danoshi commented May 10, 2024

For completness below my HTML:

return (
    <main className="flex min-h-screen flex-col p-6">
      {/* ... Image and other code remains the same */}
      <div className="flex justify-center flex-col gap-4 pt-20 md:pt-0 md:flex-row">
        <Button onClick={handleSignOut}> Sign Out</Button>

        {!showChangePassword && !showMFASetup && !showMFAVerify && (
          <form onSubmit={handleSignIn}>
            <Label htmlFor="email">Email</Label>
            <Input
              className="mt-2 mb-4 bg-transparent rounded-full "
              type="username"
              id="username"
              placeholder="Email"
              value={username}
              onChange={(e) => setUsername(e.target.value)}
            />
            <Label htmlFor="password">Password</Label>
            <Input
              className="mt-2 mb-4 bg-transparent rounded-full "
              type="password"
              id="password"
              placeholder="Password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
            />
            <Button type="submit" className="w-full mt-6 rounded-full ">
              Login
            </Button>
            {error && <p className="text-red-500">{error}</p>}
          </form>
        )}
        {showChangePassword && (
          <form onSubmit={handleSignIn}>
            <Input
              className="mt-2 mb-4 bg-transparent rounded-full "
              type="password"
              placeholder="New Password"
              value={newPassword}
              onChange={(e) => setNewPassword(e.target.value)}
            />
            <Input
              className="mt-2 mb-4 bg-transparent rounded-full "
              type="password"
              placeholder="Confirm New Password"
              value={confirmPassword}
              onChange={(e) => setConfirmPassword(e.target.value)}
            />
            <Button type="submit" className="w-full mt-6 rounded-full ">
              Change Password
            </Button>
          </form>
        )}
        {showMFASetup && (
          <form onSubmit={handleSignIn}>
            {/* ... MFA setup form (provide instructions and input for MFA code) */}
            <p>Please scan the QR code with your MFA app.</p>
            {/* The code which is generated (display as QR code or clickable link) */}
            <Canvas
              text={setupUri}
              options={{
                errorCorrectionLevel: 'M',
                margin: 3,
                scale: 4,
                width: 200,
                color: {
                  dark: '#010599FF',
                  light: '#FFBF60FF',
                },
              }}
            />
            {/* Input for the MFA code from the user */}
            <Input
              className="mt-2 mb-4 bg-transparent rounded-full"
              type="text"
              placeholder="Enter OTP code"
              value={otpCode}
              onChange={(e) => setOtpCode(e.target.value)}
            />
            <Button type="submit" className="w-full mt-6 rounded-full">
              Confirm MFA
            </Button>
          </form>
        )}
        {showMFAVerify && (
          <form onSubmit={handleSignIn}>
            {/* ... MFA verification form (input for MFA code) */}
            <Input
              className="mt-2 mb-4 bg-transparent rounded-full"
              type="text"
              placeholder="Enter OTP code"
              value={otpCode}
              onChange={(e) => setOtpCode(e.target.value)}
            />
            <Button type="submit" className="w-full mt-6 rounded-full">
              Submit
            </Button>
          </form>
        )}
      </div>
    </main>
  );

@cwomack
Copy link
Contributor

cwomack commented May 10, 2024

@danoshi, can you clarify what application you're using for your QR code? The code mismatch error is usually due to there being a "off by one" scenario due to API's running 2x, but want to understand how you've set up Auth better to diagnose this.

@cwomack cwomack added question General question Auth Related to Auth components/category pending-response Issue is pending response from the issue requestor and removed pending-triage Issue is pending triage labels May 10, 2024
@danoshi
Copy link
Author

danoshi commented May 10, 2024

I actually scanned the QR code in my google authenticator app.
To create the QR code i used the npm package next-qrcode.

Here is how I set it up:

import { useQRCode } from 'next-qrcode';
const { Canvas } = useQRCode();
            <Canvas
              text={setupUri} // the url from the object
              options={{
                errorCorrectionLevel: 'M',
                margin: 3,
                scale: 4,
                width: 200,
                color: {
                  dark: '#010599FF',
                  light: '#FFBF60FF',
                },
              }}
            />

@github-actions github-actions bot removed the pending-response Issue is pending response from the issue requestor label May 10, 2024
@cwomack
Copy link
Contributor

cwomack commented May 13, 2024

@danoshi, can you confirm if you're getting the secrets back from Cognito when making your Authentication calls? Are you able to use the third party Authenticator app to manually input the code rather than using the QR code?

@cwomack cwomack added the pending-response Issue is pending response from the issue requestor label May 13, 2024
@danoshi
Copy link
Author

danoshi commented May 13, 2024

Hi, as you can see below I can confirm that I get the secret back and yes I tried to scan the code without success, as well as manuelly input it into the google authenticator app but this as well without success.
grafik
I always get code mismatch in the console as an error.

x-amzn-errortype EnableSoftwareTokenMFAException:
x-amzn-errormessage Code mismatch
-- --
x-amzn-requestid 54d1174c-3f64-4222-adf4-3cd82d32b4c8
-- --

@github-actions github-actions bot removed the pending-response Issue is pending response from the issue requestor label May 13, 2024
@danoshi
Copy link
Author

danoshi commented May 17, 2024

Is there any update? @cwomack
Unfortunately, I have the requirement to use my own custom UI so there is no way for me to use the Authenticator app.

@israx
Copy link
Contributor

israx commented May 17, 2024

hello @danoshi . Sorry for any inconvenience using the library. Can you share the request payload after calling confirmSignIn with the 6 digit otp code retrieved from your authenticator app ?

@israx
Copy link
Contributor

israx commented May 17, 2024

also how is your app retrieving this otp code ?

@danoshi
Copy link
Author

danoshi commented May 17, 2024

Here is the payload

{"UserCode":"881868","Session":"AYABeOJlH5hsFwQrcuHccqKgvmUAHQABAAdTZXJ2aWNlABBDb2duaXRvVXNlclBvb2xzAAEAB2F3cy1rbXMATmFybjphd3M6a21zOmV1LWNlbnRyYWwtMTo1OTA0OTA4MDk4NTg6a2V5LzRkMmU1YTdmLTFjZDctNDljOS04ZmFjLTJkOWRjYjVjZWY5ZgC4AQIBAHhKQAoXAvz_-IkJpO_9S8oXPTdmr1hCCizB3KQHYdT5uAEdzkzPUcXMkbEznl7lGhRwAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMINHi4mLQMTZ7NgS2AgEQgDt1lJQ0bRzWe6__NxrNNWs4B2sIzVmoNcNxDqph6r0mch3CpIo8zXVnULU8NDHqTiFQKhtdbDmSY_R2vgIAAAAADAAAEAAAAAAAAAAAAAAAAAA1j6tAHsfuw3BVZrZvBQGG_____wAAAAEAAAAAAAAAAAAAAAEAAAEY9-DCREK3K9XfORIm5e7NktQAPdd421k3_CAUbRgOxYsjowFwKKobimvBfGJ6G88orNOu-GCeQ-_zwhjez9yqnMV6-TQv_6GzbcrBL6_fKY73azdwXNpjPSWUKIOx7B9hQopU-eZn02y5J_2MAO81boNAxh8AXxDQiWU7heCYdfosP6C9hvgY0eJrej0VTwCfVU5fTsv5hxlk94hJSytRCHbZwXLBYmFkCbC6lXu35iQER8FUeo4I8rEtzwMkdxfRrUigXWDPXyNbYNHfyU10-quP3eMwAUL16OB0FlinQNd_xld4fM1Syk992olgmsUgIxJlVbMk7aIZ1xP_aTpbzOeHz81z-GmjUe8pVBlZKGWgkGcHxKrDSc7s3jFozAde45FRKMtuWkQ"}

Request URL:
https://cognito-idp.eu-central-1.amazonaws.com/
Request Method:
POST
Status Code:
400 Bad Request
Referrer Policy:
strict-origin-when-cross-origin
Access-Control-Allow-Origin:
*
Access-Control-Expose-Headers:
x-amzn-RequestId,x-amzn-ErrorType,x-amzn-ErrorMessage,Date
Content-Length:
70
Content-Type:
application/x-amz-json-1.1
Date:
Fri, 17 May 2024 15:15:17 GMT
X-Amzn-Errormessage:
Code mismatch
X-Amzn-Errortype:
EnableSoftwareTokenMFAException:
X-Amzn-Requestid:
f3c995f9-1423-4289-94e5-ef503239d61f

As you can see in the code which I provided above I have an input field where I add the insert the mfa code and with a button I submit it

else if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP') {
        setShowMFASetup(true);
        const totpSetupDetails = nextStep.totpSetupDetails;
        const appName = 'my_app_name';
        const setupUri = totpSetupDetails.getSetupUri(appName);
        console.log(setupUri);
        setsetupUri(setupUri.href);
        const challengeResponse = otpCode;
        const result = await confirmSignIn({
          challengeResponse,
        });
        console.log(result);
          <form onSubmit={handleSignIn}>
            {/* ... MFA setup form (provide instructions and input for MFA code) */}
            <p>Please scan the QR code with your MFA app.</p>
            {/* The code which is generated (display as QR code or clickable link) */}
            <Canvas
              text={setupUri}
              options={{
                errorCorrectionLevel: 'M',
                margin: 3,
                scale: 4,
                width: 200,
                color: {
                  dark: '#010599FF',
                  light: '#FFBF60FF',
                },
              }}
            />
            {/* Input for the MFA code from the user */}
            <Input
              className="mt-2 mb-4 bg-transparent rounded-full"
              type="text"
              placeholder="Enter the mfa"
              value={otpCode}
              onChange={(e) => setMfaCode(e.target.value)}
            />
            <Button type="submit" className="w-full mt-6 rounded-full">
              Confirm MFA
            </Button>
          </form>

Please let me know if I can provide more details to have it sorted out as soon as possible @israx @cwomack

@israx
Copy link
Contributor

israx commented May 17, 2024

I think the issue is that calling confirmSignIn in the same block of the'CONTINUE_SIGN_IN_WITH_TOTP_SETUP' clause is using a previous OTP code, hence the code miss match.

Can you separate the call of confirmSignIn after getting the 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP' step ?

The flow should be something like:

receive 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP' step -> display QR code and input field -> retrieve otp code -> submit form -> call confirmSignIn API

@danoshi
Copy link
Author

danoshi commented May 27, 2024

Thanks to your suggestions, the code works now @israx @cwomack ! I have two related questions:

  • The workflow works, but is there a way or any documentation to get the current session to restrict access to other routes if my user is not logged in?
  • Is the restriction for other routes part of the authenticator component? So that when I use the component in my root page.tsx, it will not allow access to other routes until the user is successfully authenticated?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Auth Related to Auth components/category question General question
Projects
None yet
Development

No branches or pull requests

3 participants