Skip to content

Commit 5c30741

Browse files
authored
Feature: Passwordless Login and Password Reset supports use of email mode (#3525)
## template-retail-react-app - support setting passwordless login mode in config - Set default passwordless mode to 'email' for apps created via pwa-kit-create-app - Update password reset to use email mode by default. The mode can now be configured via default.js - update passwordless login `extra-features` e2e tests - update "Continue Securely" button to "Continue" - display errors in EmailConfirmation page - added new auth-utils.js that contains utility methods for mapping passwordless and reset password API error messages to user-friendly error messages - added error message mappings for the following API error messages: - "no callback_uri is registered for client" -> "This feature is not currently available" - "Too many login requests were made. Please try again later." -> Too many requests. For your security, please wait 10 minutes before trying again. - "Monthly quota for passwordless login mode email has been exceeded" -> "This feature is not currently available" ## commerce-sdk-react - Update `getPasswordResetToken` and `authorizePasswordless` to default locale to the one in CommerceApiProvider and pass callback_uri and idp_name only when they are defined - Update `getPasswordResetToken` to return a raw response and throw an error with the error message if the status code is not 200 ## 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.
1 parent 3748b56 commit 5c30741

File tree

41 files changed

+1063
-274
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1063
-274
lines changed

e2e/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ module.exports = {
170170
PWA_E2E_USER_EMAIL: process.env.PWA_E2E_USER_EMAIL,
171171
PWA_E2E_USER_PASSWORD: process.env.PWA_E2E_USER_PASSWORD,
172172
EXTRA_FEATURES_E2E_RETAIL_APP_HOME:
173+
process.env.EXTRA_FEATURES_E2E_RETAIL_APP_HOME ||
173174
'https://scaffold-pwa-extra-features-e2e.mobify-storefront.com',
174175
EXTRA_FEATURES_E2E_RETAIL_APP_HOME_SITE: 'RefArchGlobal'
175176
}

e2e/tests/desktop/extra-features.spec.js

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ test('Verify passwordless login request', async ({page}) => {
3232
await page.locator('#email').scrollIntoViewIfNeeded()
3333
await page.fill('#email', config.PWA_E2E_USER_EMAIL)
3434

35-
await page.getByRole('button', {name: 'Continue Securely'}).click()
35+
await page.getByRole('button', {name: 'Continue'}).click()
3636

3737
await page.waitForResponse(
3838
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/login'
@@ -47,12 +47,11 @@ test('Verify passwordless login request', async ({page}) => {
4747
const params = new URLSearchParams(postData)
4848

4949
expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
50-
expect(params.get('mode')).toBe('callback')
50+
expect(params.get('mode')).toBe('email')
5151
expect(params.get('channel_id')).toBe(config.EXTRA_FEATURES_E2E_RETAIL_APP_HOME_SITE)
52-
expect(params.get('callback_uri')).toMatch(/.*\/passwordless-login-callback$/)
5352
})
5453

55-
test('Verify password reset callback request', async ({page}) => {
54+
test('Verify password reset request', async ({page}) => {
5655
let interceptedRequest = null
5756

5857
await page.route(
@@ -88,16 +87,13 @@ test('Verify password reset callback request', async ({page}) => {
8887
const params = new URLSearchParams(postData)
8988

9089
expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
91-
expect(params.get('mode')).toBe('callback')
90+
expect(params.get('mode')).toBe('email')
9291
expect(params.get('channel_id')).toBe(config.EXTRA_FEATURES_E2E_RETAIL_APP_HOME_SITE)
93-
expect(params.get('callback_uri')).toMatch(/.*\/reset-password-callback$/)
9492
expect(params.get('hint')).toBe('cross_device')
9593
})
9694

9795
// Verify on the login UI that looks different when extra login features are not enabled
98-
test('Verify password reset callback request when extra login features are not enabled', async ({
99-
page
100-
}) => {
96+
test('Verify password reset request when extra login features are not enabled', async ({page}) => {
10197
let interceptedRequest = null
10298

10399
await page.route(
@@ -132,13 +128,12 @@ test('Verify password reset callback request when extra login features are not e
132128
const params = new URLSearchParams(postData)
133129

134130
expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
135-
expect(params.get('mode')).toBe('callback')
131+
expect(params.get('mode')).toBe('email')
136132
expect(params.get('channel_id')).toBe(config.RETAIL_APP_HOME_SITE)
137-
expect(params.get('callback_uri')).toMatch(/.*\/reset-password-callback$/)
138133
expect(params.get('hint')).toBe('cross_device')
139134
})
140135

141-
test('Verify password reset request', async ({page}) => {
136+
test('Verify password reset action request', async ({page}) => {
142137
let interceptedRequest = null
143138
await page.route(
144139
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/action',

e2e/tests/mobile/extra-features.spec.js

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ test('Verify passwordless login request on mobile', async ({page}) => {
3333
await page.locator('#email').scrollIntoViewIfNeeded()
3434
await page.fill('#email', config.PWA_E2E_USER_EMAIL)
3535

36-
await page.getByRole('button', {name: 'Continue Securely'}).scrollIntoViewIfNeeded()
37-
await page.getByRole('button', {name: 'Continue Securely'}).click()
36+
await page.getByRole('button', {name: 'Continue'}).scrollIntoViewIfNeeded()
37+
await page.getByRole('button', {name: 'Continue'}).click()
3838

3939
await page.waitForResponse(
4040
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/passwordless/login'
@@ -49,14 +49,11 @@ test('Verify passwordless login request on mobile', async ({page}) => {
4949
const params = new URLSearchParams(postData)
5050

5151
expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
52-
expect(params.get('mode')).toBe('callback')
52+
expect(params.get('mode')).toBe('email')
5353
expect(params.get('channel_id')).toBe(config.EXTRA_FEATURES_E2E_RETAIL_APP_HOME_SITE)
54-
expect(params.get('callback_uri')).toMatch(/.*\/passwordless-login-callback$/)
5554
})
5655

57-
test('Verify password reset callback request on mobile (extra features enabled)', async ({
58-
page
59-
}) => {
56+
test('Verify password reset request on mobile (extra features enabled)', async ({page}) => {
6057
let interceptedRequest = null
6158

6259
await page.route(
@@ -92,13 +89,12 @@ test('Verify password reset callback request on mobile (extra features enabled)'
9289
const params = new URLSearchParams(postData)
9390

9491
expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
95-
expect(params.get('mode')).toBe('callback')
92+
expect(params.get('mode')).toBe('email')
9693
expect(params.get('channel_id')).toBe(config.EXTRA_FEATURES_E2E_RETAIL_APP_HOME_SITE)
97-
expect(params.get('callback_uri')).toMatch(/.*\/reset-password-callback$/)
9894
expect(params.get('hint')).toBe('cross_device')
9995
})
10096

101-
test('Verify password reset callback request on mobile when extra login features are not enabled', async ({
97+
test('Verify password reset request on mobile when extra login features are not enabled', async ({
10298
page
10399
}) => {
104100
let interceptedRequest = null
@@ -136,13 +132,12 @@ test('Verify password reset callback request on mobile when extra login features
136132
const params = new URLSearchParams(postData)
137133

138134
expect(params.get('user_id')).toBe(config.PWA_E2E_USER_EMAIL)
139-
expect(params.get('mode')).toBe('callback')
135+
expect(params.get('mode')).toBe('email')
140136
expect(params.get('channel_id')).toBe(config.RETAIL_APP_HOME_SITE)
141-
expect(params.get('callback_uri')).toMatch(/.*\/reset-password-callback$/)
142137
expect(params.get('hint')).toBe('cross_device')
143138
})
144139

145-
test('Verify password reset request on mobile', async ({page}) => {
140+
test('Verify password reset action request on mobile', async ({page}) => {
146141
let interceptedRequest = null
147142
await page.route(
148143
'**/mobify/slas/private/shopper/auth/v1/organizations/*/oauth2/password/action',

packages/commerce-sdk-react/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## v4.4.0-dev (Dec 17, 2025)
22
- [Bugfix]Ensure code_verifier can be optional in resetPassword call [#3567](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3567)
33
- [Improvement] Strengthening typescript types on custom endpoint options and fetchOptions types [#3589](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3589)
4+
- [Feature] update `authorizePasswordless`, `getPasswordResetToken`, and `resetPassword` to support use of `email` mode [#3525](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3525)
45

56
## v4.3.0 (Dec 17, 2025)
67

0 commit comments

Comments
 (0)