Skip to content
Merged
Show file tree
Hide file tree
Changes from 103 commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
7877887
@W-20279798 support setting passwordless login mode in config (#3492)
hajinsuha1 Dec 10, 2025
22b6a36
Merge branch 'develop' into feature/email-otp
hajinsuha1 Dec 17, 2025
c646e44
@W-20443849 Set default passwordless mode to 'email' for apps created…
hajinsuha1 Dec 22, 2025
bd6d1d0
Merge branch 'develop' into feature/email-otp
hajinsuha1 Dec 29, 2025
a903665
One click checkout
syadupathi-sf Dec 30, 2025
1e7e5fd
changes to fix install, tests and lint - needs to be reviewed
syadupathi-sf Dec 30, 2025
b707b09
Change log
syadupathi-sf Dec 30, 2025
a72864b
revert the test change in pwa-kit-runtime
syadupathi-sf Dec 30, 2025
0fd5d2c
Change commerce-sdk-react package-lock in an attempt to get the CI wo…
syadupathi-sf Dec 30, 2025
fdb57a2
Increase bundle size of template-retail-react-app by 1KB
syadupathi-sf Dec 30, 2025
f005c92
pull in OTP Auth modal changes from 1 click checkout feature branch
hajinsuha1 Dec 31, 2025
65dfe27
integrate OTPAuth modal in login flows
hajinsuha1 Dec 31, 2025
434ae12
update passwordless login component to not hide fields when submit is…
hajinsuha1 Dec 31, 2025
78fd7e2
add back changes made in feature/email-otp branch
hajinsuha1 Dec 31, 2025
a0343e9
remove redundant calls to merge basket
hajinsuha1 Dec 31, 2025
d9a6b12
move handleMergeBaskets to a custom hook
hajinsuha1 Dec 31, 2025
823ac62
add unit tests
hajinsuha1 Dec 31, 2025
d56b87a
update changelog
hajinsuha1 Dec 31, 2025
d34ec56
Revert "move handleMergeBaskets to a custom hook"
hajinsuha1 Dec 31, 2025
11be87e
@W-20342599 Password Reset uses `email` mode (#3547)
hajinsuha1 Jan 2, 2026
4d1a5aa
Enhance passwordless login configuration by adding token length optio…
hajinsuha1 Jan 6, 2026
355bc0d
@W-20542850 Remove promotion from Shipping Method summary view (#3563)
syadupathi-sf Jan 7, 2026
d9ed864
@W-20279800 Update Passwordless E2E tests and change "Continue Secure…
hajinsuha1 Jan 8, 2026
229221c
Merge branch 'feature/email-otp' into W-20448811-shopper-can-manually…
hajinsuha1 Jan 8, 2026
f032e1c
update translations
hajinsuha1 Jan 8, 2026
e73c04c
update pwa-kit-create-app changelog
hajinsuha1 Jan 8, 2026
cd05b1f
fix translations
hajinsuha1 Jan 8, 2026
96f1b89
W-19728108 Add amount to payment instrument in the basket (#3568)
syadupathi-sf Jan 8, 2026
77d1147
E2E test updates Passwordless login manual input of OTP (#3558)
hajinsuha1 Jan 8, 2026
07802f3
Merge branch 'develop' into feature/email-otp
hajinsuha1 Jan 9, 2026
c0aedcb
lint
hajinsuha1 Jan 9, 2026
f773ee4
Move tokenLength configuration from passwordless to login for future …
hajinsuha1 Jan 9, 2026
3d27d0b
fix incorrect resetPasswordLandingPath in usePasswordReset after merg…
hajinsuha1 Jan 12, 2026
e49c9be
Merge branch 'develop' into feature/email-otp
hajinsuha1 Jan 12, 2026
3cfece1
fix failing unit test after merge from develop
hajinsuha1 Jan 12, 2026
5c8c6ce
W-19728108 Amount for the registered shopper (#3572)
syadupathi-sf Jan 12, 2026
c02836d
Merge branch 'develop' into feature/email-otp
hajinsuha1 Jan 13, 2026
8fd1ab2
W-20892453 Remove store pickup shipping option (#3575)
syadupathi-sf Jan 14, 2026
81973db
@W-20892497 Show Phone number in Contact Info summary (#3576)
syadupathi-sf Jan 14, 2026
128ccd5
@W-20892554 Show spinner when user registration checkbox is clicked (…
syadupathi-sf Jan 15, 2026
a5deb6c
@W-20892592 Remove gift messaging for multi shipment (#3579)
syadupathi-sf Jan 15, 2026
3d79932
@W-20890250 Handle request limit and monthly quota error states for p…
hajinsuha1 Jan 16, 2026
892ef8c
Merge branch 'develop' into feature/email-otp
hajinsuha1 Jan 16, 2026
80c1c80
@W-20892530 @W-20892577 Billing Address Validation and Using contact …
syadupathi-sf Jan 16, 2026
0e79176
Merge branch 'develop' into feature/1cc_merge
syadupathi-sf Jan 16, 2026
a0d8325
@W-20931438 Add spinner for place order button (#3587)
syadupathi-sf Jan 20, 2026
35a9a4d
Update isomorphic version to the newly released version (#3592)
syadupathi-sf Jan 21, 2026
d6fe32c
Merge branch 'develop' into feature/1cc_merge
syadupathi-sf Jan 21, 2026
b9cb29d
Fix SDK tests (#3593)
syadupathi-sf Jan 21, 2026
076b1ac
refactor auth so locale is sent via parameters instead of in the Auth…
hajinsuha1 Jan 21, 2026
b0ca814
Refactor URL handling by replacing buildAbsoluteUrl with absoluteUrl …
hajinsuha1 Jan 21, 2026
3c05026
Merge branch 'develop' into feature/email-otp
hajinsuha1 Jan 22, 2026
36e1b20
Update error message when shopper exceedes request limit for password…
hajinsuha1 Jan 22, 2026
3e9e385
Merge branch 'feature/email-otp' of https://github.com/SalesforceComm…
hajinsuha1 Jan 22, 2026
b7515c4
@W-20931758 Allow guest shopper to change payment (#3591)
syadupathi-sf Jan 22, 2026
abff98d
Apply suggestion from @alexvuong
hajinsuha1 Jan 22, 2026
c292a78
@W-21000333: [BOPIS] Should skip pick up address (#3601)
dannyphan2000 Jan 23, 2026
fe0a623
address feedback:
hajinsuha1 Jan 23, 2026
5f31e30
Merge branch 'feature/email-otp' of https://github.com/SalesforceComm…
hajinsuha1 Jan 23, 2026
bc6f621
lint
hajinsuha1 Jan 23, 2026
9fa4455
W-21005962 Disable user registration when billing address is not vali…
syadupathi-sf Jan 23, 2026
411fc67
@W-21000338: [BOPIS] Auto-populate billing address with default addre…
dannyphan2000 Jan 25, 2026
dbb914e
@W-21006290: [BOPIS] Continue to Shipping Address label fix for BOPIS…
dannyphan2000 Jan 25, 2026
9c618de
@W-21000344: [BOPIS] Pickup address component enhancement (#3607)
dannyphan2000 Jan 25, 2026
753f306
W-21005976 Newly registered user can change payment (#3608)
syadupathi-sf Jan 26, 2026
c766b59
Merge branch 'develop' into feature/email-otp
hajinsuha1 Jan 26, 2026
f4852df
update copyright date for new files
hajinsuha1 Jan 26, 2026
7b6ee61
Merge branch 'feature/email-otp' into W-20448811-shopper-can-manually…
hajinsuha1 Jan 27, 2026
57d8961
Update OTP token length configuration to allow environment variable o…
hajinsuha1 Jan 28, 2026
6f45d2b
Refactor authentication modal tests and cleanup unused constants
hajinsuha1 Jan 28, 2026
32106db
Merge branch 'develop' into W-20448811-shopper-can-manually-enter-otp…
hajinsuha1 Jan 28, 2026
4f04c56
@W-21038080: [1CC][PWA] Add new feature toggle in config to template …
dannyphan2000 Jan 28, 2026
e8ffba8
Refactor error handling in authentication flows to use new error mess…
hajinsuha1 Jan 28, 2026
c672d31
Enhance OTP input field configuration and validation
hajinsuha1 Jan 28, 2026
8a25361
@W-21038080: Rework to use billing address phone number for guest sho…
dannyphan2000 Jan 28, 2026
aff72eb
@ W-20540715 Address 1CC feature branch review comments (#3619)
syadupathi-sf Jan 29, 2026
b73115a
Merge branch 'develop' into feature/1cc_merge
syadupathi-sf Jan 30, 2026
44b2347
test
syadupathi-sf Jan 30, 2026
7ed0da9
passwordless mode updates
syadupathi-sf Jan 30, 2026
e6b9f3d
fix unit test
syadupathi-sf Jan 30, 2026
2720a5c
Merge branch 'feature/1cc_merge' into W-20448811-shopper-can-manually…
hajinsuha1 Jan 30, 2026
25e4f4f
increase bundle size of template-retail-react-app
hajinsuha1 Jan 30, 2026
34507b7
update translations
hajinsuha1 Jan 30, 2026
23a40e4
lint
hajinsuha1 Jan 30, 2026
77551f2
@W-20892603: Remove empty shipment fix (#3622)
dannyphan2000 Jan 30, 2026
3c2123a
Merge branch 'feature/1cc_merge' into W-20448811-shopper-can-manually…
hajinsuha1 Jan 30, 2026
0f6b842
Fix contact-info page not showing check your email modal when one-cli…
hajinsuha1 Jan 30, 2026
88419a6
reset form only if view is not email
hajinsuha1 Jan 30, 2026
bef76be
revert unnecessary changes made in login/index.jsx
hajinsuha1 Jan 30, 2026
60d3614
Update error handling in one-click contact info component to use the …
hajinsuha1 Jan 30, 2026
6649505
Update packages/template-retail-react-app/app/pages/checkout-one-clic…
syadupathi-sf Jan 30, 2026
5144503
revert to generic error message as per code review comment
syadupathi-sf Jan 30, 2026
2a74e96
console warn for null and undefined token lengths
hajinsuha1 Jan 30, 2026
e3c6e53
Merge branch 'feature/1cc_merge' into W-20448811-shopper-can-manually…
hajinsuha1 Jan 30, 2026
93c68c5
Merge branch 'develop' into W-20448811-shopper-can-manually-enter-otp…
hajinsuha1 Feb 2, 2026
482cd49
Add comment to default.js about tokenLength
hajinsuha1 Feb 3, 2026
babac43
Refactor OTP token length validation handling in default.js. Remove r…
hajinsuha1 Feb 3, 2026
ebdac22
add back in validation in otp-auth
hajinsuha1 Feb 3, 2026
b542c8d
lint
hajinsuha1 Feb 3, 2026
9cec46e
Merge branch 'develop' into W-20448811-shopper-can-manually-enter-otp…
hajinsuha1 Feb 3, 2026
88643c6
fix merge errors
hajinsuha1 Feb 3, 2026
cd0d3d1
update pwa-kit-create-app utils.js with validateOtpTokenLength method
hajinsuha1 Feb 3, 2026
644928d
update pwa-kit-create-app @salesforce/retail-react-app/config/utils.j…
hajinsuha1 Feb 3, 2026
c3752d2
Merge branch 'develop' into W-20448811-shopper-can-manually-enter-otp…
hajinsuha1 Feb 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions e2e/tests/desktop/extra-features.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,49 @@ test('Verify passwordless login request', async ({page}) => {
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/login'
)

// Verify the passwordless login request
expect(interceptedRequest).toBeTruthy()
expect(interceptedRequest.method()).toBe('POST')

const postData = interceptedRequest.postData()
let postData = interceptedRequest.postData()
expect(postData).toBeTruthy()

const params = new URLSearchParams(postData)
let params = new URLSearchParams(postData)

expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
expect(params.get('mode')).toBe('email')
expect(params.get('channel_id')).toBe(config.EXTRA_FEATURES_E2E_RETAIL_APP_HOME_SITE)

await page.route(
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/token',
(route) => {
interceptedRequest = route.request()
route.continue()
}
)

// 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.

const otpInputs = page.locator('input[inputmode="numeric"][maxlength="1"]')
await otpInputs.first().waitFor()

// Fill each input field with one digit
for (let i = 0; i < 8; i++) {
await otpInputs.nth(i).fill(otpCode[i])
}

await page.waitForResponse(
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/token'
)

// Verify the passwordless login token request
expect(interceptedRequest).toBeTruthy()
expect(interceptedRequest.method()).toBe('POST')
postData = interceptedRequest.postData()
expect(postData).toBeTruthy()
params = new URLSearchParams(postData)
expect(params.get('pwdless_login_token')).toBe(otpCode)
expect(params.get('hint')).toBe('pwdless_login')
})

test('Verify password reset request', async ({page}) => {
Expand Down
36 changes: 34 additions & 2 deletions e2e/tests/mobile/extra-features.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,49 @@ test('Verify passwordless login request on mobile', async ({page}) => {
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/login'
)

// Verify the passwordless login request
expect(interceptedRequest).toBeTruthy()
expect(interceptedRequest.method()).toBe('POST')

const postData = interceptedRequest.postData()
let postData = interceptedRequest.postData()
expect(postData).toBeTruthy()

const params = new URLSearchParams(postData)
let params = new URLSearchParams(postData)

expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
expect(params.get('mode')).toBe('email')
expect(params.get('channel_id')).toBe(config.EXTRA_FEATURES_E2E_RETAIL_APP_HOME_SITE)

await page.route(
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/token',
(route) => {
interceptedRequest = route.request()
route.continue()
}
)

// Wait for OTP input fields to appear and fill the 8-digit code
const otpCode = '12345678' // Replace with actual OTP code
const otpInputs = page.locator('input[inputmode="numeric"][maxlength="1"]')
await otpInputs.first().waitFor()

// Fill each input field with one digit
for (let i = 0; i < 8; i++) {
await otpInputs.nth(i).fill(otpCode[i])
}

await page.waitForResponse(
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/token'
)

// Verify the passwordless login token request
expect(interceptedRequest).toBeTruthy()
expect(interceptedRequest.method()).toBe('POST')
postData = interceptedRequest.postData()
expect(postData).toBeTruthy()
params = new URLSearchParams(postData)
expect(params.get('pwdless_login_token')).toBe(otpCode)
expect(params.get('hint')).toBe('pwdless_login')
})

test('Verify password reset request on mobile (extra features enabled)', async ({page}) => {
Expand Down
1 change: 1 addition & 0 deletions packages/pwa-kit-create-app/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- Add new One-Click Checkout configuration [#3609](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3609)
- Support email mode by default for passwordless login and password reset in a generated app. [#3525](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3525)
- Util function for passwordless callback URI [#3630](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3630)
- Add `tokenLength` to login configuration [#3554](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3554)

## v3.15.0 (Dec 17, 2025)
- Add new Google Cloud API configuration and Bonus Product configuration [#3523](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3523)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
/* eslint-disable @typescript-eslint/no-var-requires */
const sites = require('./sites.js')
const {parseSettings} = require('./utils.js')
const {parseSettings, validateOtpTokenLength} = require('./utils.js')

module.exports = {
app: {
Expand Down Expand Up @@ -57,6 +57,9 @@ module.exports = {
interpretPlusSignAsSpace: false
},
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: validateOtpTokenLength(process.env.OTP_TOKEN_LENGTH),
passwordless: {
// Enables or disables passwordless login for the site. Defaults to: false
{{#if answers.project.demo.enableDemoSettings}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,42 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

/**
* Valid OTP token lengths supported by the authentication system.
* These values are enforced to ensure compatibility with the OTP verification flow.
*/
const VALID_OTP_TOKEN_LENGTHS = [6, 8]
const DEFAULT_OTP_TOKEN_LENGTH = 8

/**
* Validates and normalizes the OTP token length configuration.
* Throws an error if the token length is invalid.
*
* @param {string|number|undefined} tokenLength - The token length from config or env var
* @returns {number} Validated token length (6 or 8)
* @throws {Error} If tokenLength is invalid (not 6 or 8)
*/
function validateOtpTokenLength(tokenLength) {
// If undefined, return default
if (tokenLength === undefined) {
return DEFAULT_OTP_TOKEN_LENGTH
}

// Parse to number (handles string numbers like "6" or "8")
const parsedLength = Number(tokenLength)

// Check if it's one of the allowed values (includes() will return false for NaN or invalid numbers)
if (!VALID_OTP_TOKEN_LENGTHS.includes(parsedLength)) {
throw new Error(
`Invalid OTP token length: ${tokenLength}. Valid values are ${VALID_OTP_TOKEN_LENGTHS.join(
' or '
)}. `
)
}

return parsedLength
}

/**
* Safely parses settings from either a JSON string or object
* @param {string|object} settings - The settings
Expand All @@ -30,5 +66,8 @@ function parseSettings(settings) {
}

module.exports = {
parseSettings
parseSettings,
validateOtpTokenLength,
DEFAULT_OTP_TOKEN_LENGTH,
VALID_OTP_TOKEN_LENGTHS
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
/* eslint-disable @typescript-eslint/no-var-requires */
const sites = require('./sites.js')
const {parseSettings} = require('./utils.js')
const {parseSettings, validateOtpTokenLength} = require('./utils.js')

module.exports = {
app: {
Expand Down Expand Up @@ -57,6 +57,9 @@ module.exports = {
interpretPlusSignAsSpace: false
},
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: validateOtpTokenLength(process.env.OTP_TOKEN_LENGTH),
passwordless: {
// Enables or disables passwordless login for the site. Defaults to: false
{{#if answers.project.demo.enableDemoSettings}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,42 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

/**
* Valid OTP token lengths supported by the authentication system.
* These values are enforced to ensure compatibility with the OTP verification flow.
*/
const VALID_OTP_TOKEN_LENGTHS = [6, 8]
const DEFAULT_OTP_TOKEN_LENGTH = 8

/**
* Validates and normalizes the OTP token length configuration.
* Throws an error if the token length is invalid.
*
* @param {string|number|undefined} tokenLength - The token length from config or env var
* @returns {number} Validated token length (6 or 8)
* @throws {Error} If tokenLength is invalid (not 6 or 8)
*/
function validateOtpTokenLength(tokenLength) {
// If undefined, return default
if (tokenLength === undefined) {
return DEFAULT_OTP_TOKEN_LENGTH
}

// Parse to number (handles string numbers like "6" or "8")
const parsedLength = Number(tokenLength)

// Check if it's one of the allowed values (includes() will return false for NaN or invalid numbers)
if (!VALID_OTP_TOKEN_LENGTHS.includes(parsedLength)) {
throw new Error(
`Invalid OTP token length: ${tokenLength}. Valid values are ${VALID_OTP_TOKEN_LENGTHS.join(
' or '
)}. `
)
}

return parsedLength
}

/**
* Safely parses settings from either a JSON string or object
* @param {string|object} settings - The settings
Expand All @@ -30,5 +66,8 @@ function parseSettings(settings) {
}

module.exports = {
parseSettings
parseSettings,
validateOtpTokenLength,
DEFAULT_OTP_TOKEN_LENGTH,
VALID_OTP_TOKEN_LENGTHS
}
1 change: 1 addition & 0 deletions packages/template-retail-react-app/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [Feature] Update passwordless login and password reset to use email mode by default. The mode can now be configured across the login page, auth modal, and checkout page [#3525](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3525)
- Update "Continue Securely" button text to "Continue" for passwordless login [#3556](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3556)
- Util function for passwordless callback URI [#3630](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3630)
- Allow shopper to manually input OTP during passwordless login [#3554](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3554)

## v8.3.0 (Dec 17, 2025)
- [Bugfix] Fix Forgot Password link not working from Account Profile password update form [#3493](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3493)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {useUsid, useCustomerType, useDNT} from '@salesforce/commerce-sdk-react'
import {useCurrentCustomer} from '@salesforce/retail-react-app/app/hooks/use-current-customer'
import {useOtpInputs} from '@salesforce/retail-react-app/app/hooks/use-otp-inputs'
import {useCountdown} from '@salesforce/retail-react-app/app/hooks/use-countdown'
import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'

const OtpAuth = ({
isOpen,
Expand All @@ -35,9 +36,20 @@ const OtpAuth = ({
handleSendEmailOtp,
handleOtpVerification,
onCheckoutAsGuest,
isGuestRegistration = false
isGuestRegistration = false,
hideCheckoutAsGuestButton = false
}) => {
const OTP_LENGTH = 8
const {tokenLength} = getConfig().app.login
const parsedLength = Number(tokenLength)
const isValidOtpLength = parsedLength === 6 || parsedLength === 8
const OTP_LENGTH = isValidOtpLength ? parsedLength : 8

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

)
}

const [isVerifying, setIsVerifying] = useState(false)
const [error, setError] = useState('')
const [resendTimer, setResendTimer] = useCountdown(0)
Expand Down Expand Up @@ -269,35 +281,37 @@ const OtpAuth = ({

{/* Buttons */}
<HStack spacing={4} width="100%" justifyContent="center">
<Button
onClick={handleCheckoutAsGuest}
variant="solid"
size="lg"
minWidth="160px"
isDisabled={isVerifying}
bg="gray.50"
color="gray.800"
fontWeight="bold"
border="none"
_hover={{
bg: 'gray.100'
}}
_active={{
bg: 'gray.200'
}}
>
{isGuestRegistration ? (
<FormattedMessage
defaultMessage="Cancel"
id="otp.button.cancel_guest_registration"
/>
) : (
<FormattedMessage
defaultMessage="Checkout as a Guest"
id="otp.button.checkout_as_guest"
/>
)}
</Button>
{!hideCheckoutAsGuestButton && (
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

in the login flows we don't need to show the Checkout as Guest button so added this condition that allows us to set whether to show the button or not

Without Checkout as Guest button:
Image

With Checkout as Guest button
Image

<Button
onClick={handleCheckoutAsGuest}
variant="solid"
size="lg"
minWidth="160px"
isDisabled={isVerifying}
bg="gray.50"
color="gray.800"
fontWeight="bold"
border="none"
_hover={{
bg: 'gray.100'
}}
_active={{
bg: 'gray.200'
}}
>
{isGuestRegistration ? (
<FormattedMessage
defaultMessage="Cancel"
id="otp.button.cancel_guest_registration"
/>
) : (
<FormattedMessage
defaultMessage="Checkout as a Guest"
id="otp.button.checkout_as_guest"
/>
)}
</Button>
)}

<Button
onClick={handleResend}
Expand Down Expand Up @@ -338,7 +352,8 @@ OtpAuth.propTypes = {
handleSendEmailOtp: PropTypes.func.isRequired,
handleOtpVerification: PropTypes.func.isRequired,
onCheckoutAsGuest: PropTypes.func,
isGuestRegistration: PropTypes.bool
isGuestRegistration: PropTypes.bool,
hideCheckoutAsGuestButton: PropTypes.bool
}

export default OtpAuth
Loading
Loading