Skip to content

@W-20448811 Shopper can manually enter OTP in login flows#3554

Merged
hajinsuha1 merged 104 commits intodevelopfrom
W-20448811-shopper-can-manually-enter-otp-in-login-flows-2
Feb 4, 2026
Merged

@W-20448811 Shopper can manually enter OTP in login flows#3554
hajinsuha1 merged 104 commits intodevelopfrom
W-20448811-shopper-can-manually-enter-otp-in-login-flows-2

Conversation

@hajinsuha1
Copy link
Collaborator

@hajinsuha1 hajinsuha1 commented Dec 31, 2025

Description

Allow shopper to manually input the OTP during the passwordless login flow by displaying an OTP Auth modal after clicking "Continue Securely".

Screenshare.-.2025-12-31.2_31_41.PM.mp4

Types of Changes

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Documentation update
  • Breaking change (could cause existing functionality to not work as expected)
  • Other changes (non-breaking changes that does not fit any of the above)

Breaking changes include:

  • Removing a public function or component or prop
  • Adding a required argument to a function
  • Changing the data type of a function parameter or return value
  • Adding a new peer dependency to package.json

Changes

  • introduce a new login.tokenLength configuration in default.js that determines the number of input fields to show in the OtpAuthModal
  • update useAuthModal and login page to open the OtpAuthModal after user clicks "Continue Securely"
  • update OtpAuthModal to include a prop for hiding the Checkout as Guest button
  • update PasswordlessLogin component to not hide elements after form has been successfully submitted

How to Test-Drive This PR

Auth Modal

  1. Navigate to https://wasatch-mrt-passwordless-test.mrt-storefront-staging.com/
  2. Add any product to your cart (this is to test merge basket)
  3. Click on the profile icon on the top right
  4. Enter your email
  5. Click "Continue Securely"
  6. Verify an OTP input modal is displayed and an email containing the OTP was sent to you
  7. Enter an invalid OTP and verify Invalid token error message is displayed
    Screenshot 2026-01-28 at 2 36 48 PM
  8. Click "Resend Code" and verify another email with a new OTP was sent to you
  9. Copy the OTP and paste it into the input
  10. Verify the user is successfully logged in and redirected to the accounts page
  11. Verify the cart still contains the product you added in step 2

Login Page

  1. Add any product to your cart (this is to test merge basket)
  2. Navigate to the login page: https://wasatch-mrt-passwordless-test.mrt-storefront-staging.com/login
  3. Enter your email
  4. Click "Continue Securely"
  5. Verify an OTP input modal is displayed and an email containing the OTP was sent to you
  6. Click "Resend Code" and verify another email with a new OTP was sent to you
  7. Copy the OTP and paste it into the input
  8. Verify the user is successfully logged in and redirected to the accounts page
  9. Verify the cart still contains the product you added in step 1

Magic Link

  1. Add any product to your cart (this is to test merge basket)
  2. Navigate to the login page: https://wasatch-mrt-passwordless-test.mrt-storefront-staging.com/login
  3. Enter your email
  4. Click "Continue Securely"
  5. Click on the login link embededded in the email to login
  6. Verify the user is successfully logged in and redirected to the accounts page
  7. Verify the cart still contains the product you added in step 1

Token Length is configurable via Environment Variable

  1. Set the OTP_TOKEN_LENGTH env variable and start the app
    export OTP_TOKEN_LENGTH=6
    cd packages/template-retail-react-app
    npm start
    
  2. Verify in the passwordless login flow the input now only takes 6 digits.
  3. Set the OTP_TOKEN_LENGTH env variable to an invalid value
    export OTP_TOKEN_LENGTH=7
    npm start
    
  4. Verify in the passwordless login flow the input defaults to 8 digits and a console warn is displayed.
    Screenshot 2026-01-28 at 3 47 08 PM

Old checkout page displays "Check Your Email" modal when oneClickCheckout is disabled

  1. Navigate to the site: https://wasatch-mrt-passwordless-test.mrt-storefront-staging.com
  2. Add an item to your cart
  3. Click Proceed to Checkout
  4. Enter your email and click Secure Link
  5. Verify a "Check your email" popup is displayed and verify a login email is sent to you
    Screenshot 2026-01-30 at 2 24 55 PM

One Click Checkout works when oneClickCheckout is enabled

  1. Navigate to: https://wasatch-mrt-passwordless-poc.mrt-storefront-staging.com
  2. Add an item to your cart
  3. Enter your email and hit enter
  4. Verify the OtpAuthModal is opened with 6-digit input and an email is sent
  5. Enter the code from your email and verify you are logged in

E2E Tests

  1. Verify the updated passwordless E2E tests pass
    # Set the playwright tests to run against a `template-retail-react-app` with the new email OTP feature
    export PWA_E2E_USER_EMAIL=e2e.pwa.kit@gmail.com PWA_E2E_USER_PASSWORD=SECRET EXTRA_FEATURES_E2E_RETAIL_APP_HOME=https://wasatch-mrt-passwordless-test.mrt-storefront-staging.com
    
    npx playwright test --project=extra-features-desktop --project=extra-features-mobile --ui
    

pwa-kit-create-app

  1. Generate the project using pwa-kit-create-app
    cd ../..
    GENERATOR_PRESET=retail-react-app-demo node packages/pwa-kit-create-app/scripts/create-mobify-app-dev.js --outputDir generated-retail-react-app-demo
    
  2. Once completed open default.js in the generated app
    code generated-retail-react-app-demo/config/default.js
    
  3. Verify in default.js, app.login.passwordless.mode and app.login.resetPassword.mode is set to email and callbackURI is commented out
  4. In default.js
  5. set app.login.passwordless.enabled to true
                passwordless: {
                    // Enables or disables passwordless login for the site. Defaults to: false
                    enabled: true,
    
  6. update commerceAPI to use a private client
  7. In overrides/app/ssr.js
    1. set useSLASPrivateClient to true
    2. uncomment the applySLASPrivateClientToEndpoints property
        applySLASPrivateClientToEndpoints:
            /\/oauth2\/(token|passwordless\/(login|token)|password\/(reset|action))/,
    
  8. In overrides/app/components/_app-config/index.jsx add enablePWAKitPrivateClient={true} to the fields of CommerceApiProvider
  9. Set the token length, private client secret, and Start the app
    cd generated-retail-react-app-demo 
    export OTP_TOKEN_LENGTH=6
    export PWA_KIT_SLAS_CLIENT_SECRET=SECRET
    npm start
    
  10. Verify passwordless login works and is configured to use a 6 digit input

Checklists

General

  • Changes are covered by test cases
  • CHANGELOG.md updated with a short description of changes (not required for documentation updates)

Accessibility Compliance

You must check off all items in one of the follow two lists:

  • There are no changes to UI

or...

Localization

  • Changes include a UI text update in the Retail React App (which requires translation)

hajinsuha1 and others added 13 commits December 10, 2025 09:13
* Add passwordless login mode configuration with email as default
* Update authorizePasswordless to require mode parameter and add locale support
* Remove commented out passwordless callbackURI configuration
* Remove passwordlessCallbackURI variable and simplify callbackURI condition in authorizePasswordlessLogin
* Remove conditional callbackURI spread and add mode parameter to checkout passwordless login
* Add buildCallbackURL utility function and conditionally spread callbackURI in passwordless login
* Rename buildCallbackURL to buildAbsoluteUrl and make passwordlessLoginCallbackURI optional
* update unit tests in template-retail-react-app and fix passwordless mode in login page
* make authorizePasswordless backward compatible and add unit tests for commerce-sdk-react
* Make passwordlessLoginCallbackURI non-optional with empty string default
* update changelog
* Use endsWith() to match passwordless login landing path and add test for localized paths
Signed-off-by: Jinsu Ha <91205717+hajinsuha1@users.noreply.github.com>
@cc-prodsec
Copy link
Collaborator

cc-prodsec commented Dec 31, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

hajinsuha1 and others added 7 commits December 31, 2025 11:08
* Update getPasswordResetToken to default locale to the one in CommerceApiProvider and pass callback_uri and idp_name only when they are defined
* Update resetPassword to default hint to cross_device and pass code_verifier only when it is defined
pwa-kit-create-app
* Update default.js and /_app-config/index.jsx template to use email mode by default for passwordless login and password reset.
* Update password reset to use email mode by default. The mode can now be configured via default.js
hajinsuha1 and others added 7 commits January 6, 2026 15:20
…n and updating related components. Adjust OTP input fields in the OtpAuth component to reflect the token length from configuration.
* W-20542850 Remove promotion from Shipping Method summary view

* add translations
…ly" to "Continue" (#3556)

* update passwordless and password reset e2e tests to veirfy mode email is used

* Update EXTRA_FEATURES_E2E_RETAIL_APP_HOME to support environment variable configuration

* Update mobile e2e tests to verify 'email' mode for passwordless login and password reset requests

* update "continue securely" to "continue"
…-enter-otp-in-login-flows-2

Signed-off-by: Jinsu Ha <91205717+hajinsuha1@users.noreply.github.com>
Copy link
Contributor

@vmarta vmarta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the detailed PR description btw. Love the comprehensive ways to test the PR.

I'll continue with the PR review. Posting whatever comments I have so far.


if (!isValidOtpLength) {
console.warn(
`Invalid OTP token length: ${tokenLength}. Expected 6 or 8. Defaulting to ${OTP_LENGTH}.`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better if we enforce this 6 or 8 digit requirement somehow in both the user configuration and also in our own code. Currently, it feels like it's not easily known for other developers that there's this requirement.

Perhaps we can use constants or enums to restrict them to either 6 or 8. And add some validations somewhere to make it loud and clear of this requirement.

Copy link
Collaborator Author

@hajinsuha1 hajinsuha1 Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vmarta Makes sense! I've added a validation check to default.js. If the merchant sets an invalid OTP_TOKEN_LENGTH via env vars the app will throw an error

Arc 2026-02-03 at 11 02 06

If they update default.js with a value directly that is invalid like:

        login: {
            // The length of the token for OTP authentication. Used by passwordless login and reset password.
            // If the env var `OTP_TOKEN_LENGTH` is set, it will override the config value. Valid values are 6 or 8. Defaults to: 8
            tokenLength: 7,

They'll see a console warn when the OtpAuthModal is opened and the value would default to 8

In the docs, I'll mention setting tokenLength via env vars and not recommend setting it directly via default.js

Copy link
Contributor

@vmarta vmarta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find anything else major. So I think overall this PR is good. Although I didn't fully test the different scenarios (as described in the PR), the few ones I did were functioning as expected.

Yeah, I think the biggest thing for me is the validation and configuration of 6 or 8 digits.

)

// Wait for OTP input fields to appear and fill the 8-digit code
const otpCode = '12345678' // Replace with actual OTP code
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, thank you for updating the E2E tests too.

interpretPlusSignAsSpace: false
},
login: {
tokenLength: process.env.OTP_TOKEN_LENGTH || 8,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the comment that was added to the configuration files found in the create-app package. Let's copy that over to here as well.

@jeremy-jung1
Copy link
Collaborator

Perhaps this was an issue that has already been present but I'm seeing that the product I add to the cart is not merging with the ones already in my account. Video sent via Slack

vmarta
vmarta previously approved these changes Feb 3, 2026
Copy link
Contributor

@vmarta vmarta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing the OTP token length.

…-in-login-flows-2

Signed-off-by: Jinsu Ha <91205717+hajinsuha1@users.noreply.github.com>
vmarta
vmarta previously approved these changes Feb 3, 2026
jeremy-jung1
jeremy-jung1 previously approved these changes Feb 3, 2026
@hajinsuha1 hajinsuha1 dismissed stale reviews from jeremy-jung1 and vmarta via cd0d3d1 February 3, 2026 20:55
vmarta
vmarta previously approved these changes Feb 3, 2026
jeremy-jung1
jeremy-jung1 previously approved these changes Feb 3, 2026
vmarta
vmarta previously approved these changes Feb 3, 2026
…-in-login-flows-2

Signed-off-by: Jinsu Ha <91205717+hajinsuha1@users.noreply.github.com>
@hajinsuha1 hajinsuha1 dismissed stale reviews from vmarta and jeremy-jung1 via c3752d2 February 4, 2026 14:33
@hajinsuha1 hajinsuha1 merged commit 9b5050f into develop Feb 4, 2026
42 checks passed
@hajinsuha1 hajinsuha1 deleted the W-20448811-shopper-can-manually-enter-otp-in-login-flows-2 branch February 4, 2026 17:08
syadupathi-sf pushed a commit that referenced this pull request Feb 4, 2026
- introduce a new `login.tokenLength` configuration in default.js that determines the number of input fields to show in the `OtpAuthModal`
- update `useAuthModal` and login page to open the `OtpAuthModal` after user clicks "Continue Securely"
- update `OtpAuthModal` to include a prop for hiding the `Checkout as Guest` button
- update `PasswordlessLogin` component to not hide elements after form has been successfully submitted
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants