Repository: SalesforceCommerceCloud/pwa-kit
Pull request #2340: Migrate `ssr.js` from `template-retail-react-app` (develop) into feature/extensibility-v2
Author: login: bendvc
Labels: name: skip changelog
description: Skip the "Changelog Check" GitHub Actions step even if the Changelog.md files are not updated
Created: 2025-03-28T22:39:17Z | Merged: 2025-04-03T17:42:38Z

# Description

A lot of work was done in `ssr.js` for password reset, and social login, I didn't migrate those changes to work with extensibility. This PR does that.

# Testing

> _I've deployed this branch to MRT, you can see it [here](https://scaffold-pwa-bens-playground.mobify-storefront.com/). This isn't a direct deployment of the branch as I had to set up private client in over to have these features work, but I didn't want to commit those changes. Also, if you want to set up your own environment you'll have to ensure you have all the correct private client keys and marketing cloud keys set up, you can see them here. Additionally you'll have to ensure that the the environment you set up is listed as a valid callback URI in slas (https://kv7kzm78.api.commercecloud.salesforce.com/shopper/auth-admin/v1/sso/login). In short it's easier to test my environment._

## Social Login

1. Goto https://scaffold-pwa-bens-playground.mobify-storefront.com/
2. Click the profile button in the header to open the login modal.
3. Click the google login button. 
4. You should login whether you have previously created an account of not (I believe) ... this will use your active google account, so probably your work acount.

## Passwordless Login

1. Create an account manual if you haven't already done so.  (I like to use https://temp-mail.org/ to create a temporary email address). 
2. If you had to create an account, logout as you'll probably be logged in after creating the account.
3. Now open the login modal and put your email address in and click "continue securely"
4. Wait for the email to arrive and follow the link.
5. You browser should automatically log you in.

## Password Reset
1. Using the previously create account, open the login modal..
2. Put your email address in the field and click "password"
3. Under the password field you'll see a "reset password" link, click it
4. You'll be presented with a form with your email, click the "reset password" button.
5. You should get an email in your inbox with a link, click it and enter a new password.
6. Login with that new password to confirm it was changed.


Diff:
diff --git a/packages/extension-chakra-storefront/config/default.json b/packages/extension-chakra-storefront/config/default.json
index 1cada838d5..9cfa9e2a70 100644
--- a/packages/extension-chakra-storefront/config/default.json
+++ b/packages/extension-chakra-storefront/config/default.json
@@ -96,9 +96,6 @@
         },
         "SocialRedirect": {
             "path": "/social-redirect"
-        },
-        "WishList": {
-            "path": "/account/wishlist"
         }
     },
     "search": {
diff --git a/packages/extension-chakra-storefront/src/components/social-login/index.jsx b/packages/extension-chakra-storefront/src/components/social-login/index.jsx
index 21fa63028f..2da670e0a4 100644
--- a/packages/extension-chakra-storefront/src/components/social-login/index.jsx
+++ b/packages/extension-chakra-storefront/src/components/social-login/index.jsx
@@ -11,8 +11,8 @@ import {defineMessage, useIntl} from 'react-intl'
 import {Button} from '@chakra-ui/react'
 import logger from '../../utils/logger-instance'
 import {useAuthHelper, AuthHelpers} from '@salesforce/commerce-sdk-react'
-import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
 import {useAppOrigin} from '../../hooks/use-app-origin'
+import {useExtensionConfig} from '../../hooks/use-extension-config'
 import {setSessionJSONItem, buildRedirectURI} from '../../utils/utils'
 
 // Icons
@@ -48,7 +48,8 @@ const SocialLogin = ({form, idps = []}) => {
 
     // Build redirectURI from config values
     const appOrigin = useAppOrigin()
-    const redirectPath = getConfig()?.app?.login?.social?.redirectURI || ''
+    const {login: loginConfig} = useExtensionConfig()
+    const redirectPath = loginConfig?.social?.redirectURI || ''
     const redirectURI = buildRedirectURI(appOrigin, redirectPath)
 
     const isIdpValid = (name) => {
@@ -96,6 +97,7 @@ const SocialLogin = ({form, idps = []}) => {
                         return (
                             config && (
                                 <Button
+                                    key={name}
                                     onClick={() => {
                                         onSocialLoginClick(name)
                                     }}
diff --git a/packages/extension-chakra-storefront/src/components/with-layout/with-layout.tsx b/packages/extension-chakra-storefront/src/components/with-layout/with-layout.tsx
index 1c586d5008..547c11e7cd 100644
--- a/packages/extension-chakra-storefront/src/components/with-layout/with-layout.tsx
+++ b/packages/extension-chakra-storefront/src/components/with-layout/with-layout.tsx
@@ -216,7 +216,9 @@ const withLayout = <P extends object>(WrappedComponent: React.ComponentType<P>)
 
         // Ensure styles.container is an object
         const containerStyles = (styles.container as React.CSSProperties) || {}
-        const headerWrapperStyles = {display: 'flex'}
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+        // @ts-ignore
+        const headerWrapperStyles = styles.headerWrapper || {}
 
         return (
             <Box className="sf-app" {...(containerStyles as any)}>
diff --git a/packages/extension-chakra-storefront/src/constants.js b/packages/extension-chakra-storefront/src/constants.js
index eb727508e4..c2d191e675 100644
--- a/packages/extension-chakra-storefront/src/constants.js
+++ b/packages/extension-chakra-storefront/src/constants.js
@@ -189,12 +189,6 @@ export const LOGIN_TYPES = {
     SOCIAL: 'social'
 }
 
-// Constants for Password Reset
-export const RESET_PASSWORD_LANDING_PATH = '/reset-password-landing'
-
-// Constants for Passwordless Login
-export const PASSWORDLESS_LOGIN_LANDING_PATH = '/passwordless-login-landing'
-
 export const PASSWORDLESS_ERROR_MESSAGES = [
     /callback_uri doesn't match/i,
     /passwordless permissions error/i,
diff --git a/packages/extension-chakra-storefront/src/hooks/use-navigation.test.js b/packages/extension-chakra-storefront/src/hooks/use-navigation.test.js
index 94219e292d..c7e2a57b58 100644
--- a/packages/extension-chakra-storefront/src/hooks/use-navigation.test.js
+++ b/packages/extension-chakra-storefront/src/hooks/use-navigation.test.js
@@ -9,13 +9,6 @@ import userEvent from '@testing-library/user-event'
 import useNavigation from './use-navigation'
 import mockConfig from '../mock-config'
 import {renderWithProviders} from '../utils/test-utils'
-import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
-
-// jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => {
-//     return {
-//         getConfig: jest.fn()
-//     }
-// })
 
 const mockHistoryPush = jest.fn()
 const mockHistoryReplace = jest.fn()
diff --git a/packages/extension-chakra-storefront/src/middleware/index.ts b/packages/extension-chakra-storefront/src/middleware/index.ts
new file mode 100644
index 0000000000..fa750096ad
--- /dev/null
+++ b/packages/extension-chakra-storefront/src/middleware/index.ts
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import jwksCachingMiddleware from './jwks-caching'
+import passwordResetMiddleware from './password-reset'
+import passwordlessMiddleware from './passwordless'
+
+export {jwksCachingMiddleware, passwordlessMiddleware, passwordResetMiddleware}
diff --git a/packages/extension-chakra-storefront/src/middleware/jwks-caching.ts b/packages/extension-chakra-storefront/src/middleware/jwks-caching.ts
new file mode 100644
index 0000000000..8970be275a
--- /dev/null
+++ b/packages/extension-chakra-storefront/src/middleware/jwks-caching.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+
+const tenantIdRegExp = /^[a-zA-Z]{4}_([0-9]{3}|s[0-9]{2}|stg|dev|prd)$/
+const shortCodeRegExp = /^[a-zA-Z0-9-]+$/
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+const jwksCachingMiddleware = () => {
+    const router = Router()
+
+    router.get(
+        '/:shortCode/:tenantId/oauth2/jwks',
+        asyncHandler(async (req: Request, res: Response, next: NextFunction) => {
+            const {shortCode, tenantId} = req.params
+            const isValidRequest = tenantIdRegExp.test(tenantId) && shortCodeRegExp.test(shortCode)
+
+            if (!isValidRequest) {
+                return res
+                    .status(400)
+                    .json({error: 'Bad request parameters: Tenant ID or short code is invalid.'})
+            }
+
+            try {
+                const JWKS_URI = `https://${shortCode}.api.commercecloud.salesforce.com/shopper/auth/v1/organizations/f_ecom_${tenantId}/oauth2/jwks`
+                const response = await fetch(JWKS_URI)
+
+                if (!response.ok) {
+                    throw new Error(`Request failed with status: ${response.status}`)
+                }
+
+                // JWKS rotate every 30 days. Cache response for 14 days
+                res.set('Cache-Control', 'public, max-age=1209600, stale-while-revalidate=86400')
+
+                return res.json(await response.json())
+            } catch (error) {
+                next(error) // Pass the error to Express error handling middleware
+            }
+        })
+    )
+
+    return router
+}
+
+export default jwksCachingMiddleware
diff --git a/packages/extension-chakra-storefront/src/middleware/password-reset.ts b/packages/extension-chakra-storefront/src/middleware/password-reset.ts
new file mode 100644
index 0000000000..8be804ae8e
--- /dev/null
+++ b/packages/extension-chakra-storefront/src/middleware/password-reset.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+import {validateSlasCallbackToken} from '../utils/slas'
+import {emailLink} from '../utils/email'
+
+interface PasswordResetOptions {
+    callbackURI?: string
+    landingPath?: string
+    shortCode: string
+    tenantId: string
+}
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+// Handles the reset password callback route. SLAS makes a POST request to this
+// endpoint sending the email address and reset password token. Then this endpoint calls
+// the sendMagicLinkEmail function to send an email with the reset password magic link.
+// https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas-password-reset.html#slas-password-reset-flow
+const passwordResetMiddleware = (options: PasswordResetOptions = {}) => {
+    const {
+        callbackURI = '/reset-password-callback',
+        landingPath = '/reset-password-landing',
+        shortCode,
+        tenantId
+    } = options
+    const router = Router()
+
+    router.post(
+        callbackURI,
+        asyncHandler(async (req, res) => {
+            const slasCallbackToken = req.headers['x-slas-callback-token']
+
+            // This will throw if the token is invalid.
+            await validateSlasCallbackToken(slasCallbackToken, shortCode, tenantId)
+
+            // Extract the base URL from the request
+            const base = `${req.protocol}://${req.get('host') || ''}`
+
+            // Extract the email_id and token from the request body
+            const {email_id, token} = req.body
+
+            // Call the emailLink function to send an email with the magic link using Marketing Cloud
+            const emailLinkResponse = await emailLink(
+                email_id,
+                process.env.MARKETING_CLOUD_RESET_PASSWORD_TEMPLATE || '',
+                `${base}${landingPath}?token=${encodeURIComponent(
+                    token
+                )}&email=${encodeURIComponent(email_id)}`
+            )
+
+            // Send the response
+            res.send(emailLinkResponse)
+        })
+    )
+
+    return router
+}
+
+export default passwordResetMiddleware
diff --git a/packages/extension-chakra-storefront/src/middleware/passwordless.ts b/packages/extension-chakra-storefront/src/middleware/passwordless.ts
new file mode 100644
index 0000000000..494f84fdb3
--- /dev/null
+++ b/packages/extension-chakra-storefront/src/middleware/passwordless.ts
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+import {validateSlasCallbackToken} from '../utils/slas'
+import {emailLink} from '../utils/email'
+
+interface PasswordlessOptions {
+    callbackURI?: string
+    landingPath?: string
+    shortCode: string
+    tenantId: string
+}
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+const passwordlessMiddleware = (options: PasswordlessOptions) => {
+    const {
+        callbackURI = '/passwordless-login-callback',
+        landingPath = '/passwordless-login-landing',
+        shortCode,
+        tenantId
+    } = options || {}
+    const router = Router()
+
+    router.post(
+        callbackURI,
+        asyncHandler(async (req, res) => {
+            const slasCallbackToken = req.headers['x-slas-callback-token']
+            const redirectUrl = req.query.redirectUrl as string
+
+            // This will throw if the token is invalid.
+            await validateSlasCallbackToken(slasCallbackToken as string, shortCode, tenantId)
+
+            // Extract the base URL from the request
+            const base = `${req.protocol}://${req.get('host') || ''}`
+
+            // Extract the email_id and token from the request body
+            const {email_id, token} = req.body
+
+            // Call the emailLink function to send an email with the magic link using Marketing Cloud
+            const emailLinkResponse = await emailLink(
+                email_id,
+                process.env.MARKETING_CLOUD_PASSWORDLESS_LOGIN_TEMPLATE || '',
+                `${base}${landingPath}?token=${encodeURIComponent(token)}${
+                    redirectUrl ? `&redirect_url=${encodeURIComponent(redirectUrl)}` : ''
+                }`
+            )
+
+            // Send the response
+            res.send(emailLinkResponse)
+        })
+    )
+
+    return router
+}
+
+export default passwordlessMiddleware
diff --git a/packages/extension-chakra-storefront/src/pages/checkout/index.jsx b/packages/extension-chakra-storefront/src/pages/checkout/index.jsx
index 78be0f3a99..4e62930e72 100644
--- a/packages/extension-chakra-storefront/src/pages/checkout/index.jsx
+++ b/packages/extension-chakra-storefront/src/pages/checkout/index.jsx
@@ -21,8 +21,8 @@ import {useShopperOrdersMutation, useShopperBasketsMutation} from '@salesforce/c
 import UnavailableProductConfirmationModal from '../../components/unavailable-product-confirmation-modal'
 import {API_ERROR_MESSAGE, TOAST_MESSAGE_REMOVED_ITEM_FROM_CART} from '../../constants'
 import {useToast} from '../../hooks/use-toast'
+import {useExtensionConfig} from '../../hooks'
 import LoadingSpinner from '../../components/loading-spinner'
-import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
 
 const Checkout = () => {
     const {formatMessage} = useIntl()
@@ -32,10 +32,10 @@ const Checkout = () => {
     const {data: basket} = useCurrentBasket()
     const [isLoading, setIsLoading] = useState(false)
     const {mutateAsync: createOrder} = useShopperOrdersMutation('createOrder')
-    const {passwordless = {}, social = {}} = getConfig().app.login || {}
-    const idps = social?.idps
-    const isSocialEnabled = !!social?.enabled
-    const isPasswordlessEnabled = !!passwordless?.enabled
+    const {login: loginConfig} = useExtensionConfig()
+    const isSocialEnabled = !!loginConfig?.social?.enabled
+    const isPasswordlessEnabled = !!loginConfig?.passwordless?.enabled
+    const idps = loginConfig?.social?.idps || []
 
     useEffect(() => {
         if (error || step === 4) {
diff --git a/packages/extension-chakra-storefront/src/pages/checkout/index.test.js b/packages/extension-chakra-storefront/src/pages/checkout/index.test.js
index bec58fd37d..24dce0bf35 100644
--- a/packages/extension-chakra-storefront/src/pages/checkout/index.test.js
+++ b/packages/extension-chakra-storefront/src/pages/checkout/index.test.js
@@ -310,7 +310,7 @@ test('Can proceed through checkout steps as guest', async () => {
     // Set the initial browser router path and render our component tree.
     window.history.pushState({}, 'Checkout', createPathWithDefaults('/checkout'))
     const {user} = renderWithProviders(<WrappedCheckout history={history} />, {
-        wrapperProps: {isGuest: true, siteAlias: 'uk', appConfig: mockConfig.app}
+        wrapperProps: {isGuest: true, siteAlias: 'uk', config: mockConfig}
     })
 
     // Wait for checkout to load and display first step
@@ -437,7 +437,7 @@ test('Can proceed through checkout as registered customer', async () => {
             isGuest: false,
             siteAlias: 'uk',
             locale: {id: 'en-GB'},
-            appConfig: mockConfig.app
+            config: mockConfig
         }
     })
 
@@ -541,7 +541,7 @@ test('Can edit address during checkout as a registered customer', async () => {
             isGuest: false,
             siteAlias: 'uk',
             locale: {id: 'en-GB'},
-            appConfig: mockConfig.app
+            config: mockConfig
         }
     })
 
@@ -584,7 +584,7 @@ test('Can add address during checkout as a registered customer', async () => {
             isGuest: false,
             siteAlias: 'uk',
             locale: {id: 'en-GB'},
-            appConfig: mockConfig.app
+            config: mockConfig
         }
     })
 
diff --git a/packages/extension-chakra-storefront/src/pages/checkout/partials/shipping-options.jsx b/packages/extension-chakra-storefront/src/pages/checkout/partials/shipping-options.jsx
index bcfcbae4eb..790e6f7804 100644
--- a/packages/extension-chakra-storefront/src/pages/checkout/partials/shipping-options.jsx
+++ b/packages/extension-chakra-storefront/src/pages/checkout/partials/shipping-options.jsx
@@ -83,7 +83,7 @@ export default function ShippingOptions() {
     })
 
     let shippingPriceLabel = selectedMethodDisplayPrice
-    if (selectedMethodDisplayPrice !== shippingItem.price) {
+    if (selectedMethodDisplayPrice !== shippingItem?.price) {
         const currentPrice =
             selectedMethodDisplayPrice === 0 ? freeLabel : selectedMethodDisplayPrice
 
@@ -93,7 +93,7 @@ export default function ShippingOptions() {
                 id: 'checkout_confirmation.label.shipping.strikethrough.price'
             },
             {
-                originalPrice: shippingItem.price,
+                originalPrice: shippingItem?.price,
                 newPrice: currentPrice
             }
         )
@@ -217,7 +217,7 @@ export default function ShippingOptions() {
                                     />
                                 )}
                             </Text>
-                            {selectedMethodDisplayPrice !== shippingItem.price && (
+                            {selectedMethodDisplayPrice !== shippingItem?.price && (
                                 <Text
                                     fontWeight="normal"
                                     textDecoration="line-through"
@@ -228,7 +228,7 @@ export default function ShippingOptions() {
                                     <FormattedNumber
                                         style="currency"
                                         currency={currency}
-                                        value={shippingItem.price}
+                                        value={shippingItem?.price}
                                     />
                                 </Text>
                             )}
diff --git a/packages/extension-chakra-storefront/src/pages/home/index.jsx b/packages/extension-chakra-storefront/src/pages/home/index.jsx
index 5c854605a1..396215499b 100644
--- a/packages/extension-chakra-storefront/src/pages/home/index.jsx
+++ b/packages/extension-chakra-storefront/src/pages/home/index.jsx
@@ -80,6 +80,7 @@ const Home = () => {
     /**************** Einstein ****************/
     useEffect(() => {
         einstein.sendViewPage(pathname)
+        dataCloud.sendViewPage(pathname)
     }, [])
 
     return (
diff --git a/packages/extension-chakra-storefront/src/pages/index.tsx b/packages/extension-chakra-storefront/src/pages/index.tsx
index 96633c8448..c020320fdf 100644
--- a/packages/extension-chakra-storefront/src/pages/index.tsx
+++ b/packages/extension-chakra-storefront/src/pages/index.tsx
@@ -56,7 +56,6 @@ ResetPassword.displayName = 'ResetPassword'
 LoginRedirect.displayName = 'LoginRedirect'
 ProductDetail.displayName = 'ProductDetail'
 ProductList.displayName = 'ProductList'
-Wishlist.displayName = 'Wishlist'
 
 export {
     Account,
@@ -70,6 +69,5 @@ export {
     LoginRedirect,
     ProductDetail,
     ProductList,
-    SocialLoginRedirect,
-    Wishlist
+    SocialLoginRedirect
 }
diff --git a/packages/extension-chakra-storefront/src/pages/login/index.jsx b/packages/extension-chakra-storefront/src/pages/login/index.jsx
index be1894a7f2..4a407d961b 100644
--- a/packages/extension-chakra-storefront/src/pages/login/index.jsx
+++ b/packages/extension-chakra-storefront/src/pages/login/index.jsx
@@ -33,7 +33,6 @@ import {
     INVALID_TOKEN_ERROR_MESSAGE,
     FEATURE_UNAVAILABLE_ERROR_MESSAGE,
     LOGIN_TYPES,
-    PASSWORDLESS_LOGIN_LANDING_PATH,
     PASSWORDLESS_ERROR_MESSAGES,
     USER_NOT_FOUND_ERROR
 } from '../../constants'
@@ -152,7 +151,7 @@ const Login = ({initialView = LOGIN_VIEW}) => {
     // executing a passwordless login attempt using the token. The process waits for the
     // customer baskets to be loaded to guarantee proper basket merging.
     useEffect(() => {
-        if (path === PASSWORDLESS_LOGIN_LANDING_PATH && isSuccessCustomerBaskets) {
+        if (path === loginConfig.passwordless.landingPath && isSuccessCustomerBaskets) {
             const token = decodeURIComponent(queryParams.get('token'))
             if (queryParams.get('redirect_url')) {
                 setRedirectPath(decodeURIComponent(queryParams.get('redirect_url')))
diff --git a/packages/extension-chakra-storefront/src/pages/login/index.test.js b/packages/extension-chakra-storefront/src/pages/login/index.test.js
index 3e3a705b97..ae94b05d5d 100644
--- a/packages/extension-chakra-storefront/src/pages/login/index.test.js
+++ b/packages/extension-chakra-storefront/src/pages/login/index.test.js
@@ -209,7 +209,7 @@ describe('Navigate away from login page tests', function () {
             wrapperProps: {
                 siteAlias: 'uk',
                 locale: {id: 'en-GB'},
-                appConfig: mockConfig.app,
+                config: mockConfig,
                 isGuest: true
             }
         })
diff --git a/packages/extension-chakra-storefront/src/pages/login/passwordless-landing.test.js b/packages/extension-chakra-storefront/src/pages/login/passwordless-landing.test.js
index ba84f4bf72..489f048ea0 100644
--- a/packages/extension-chakra-storefront/src/pages/login/passwordless-landing.test.js
+++ b/packages/extension-chakra-storefront/src/pages/login/passwordless-landing.test.js
@@ -105,7 +105,7 @@ describe('Passwordless landing tests', function () {
             wrapperProps: {
                 siteAlias: 'uk',
                 locale: {id: 'en-GB'},
-                appConfig: mockConfig.app
+                config: mockConfig
             }
         })
 
@@ -134,7 +134,7 @@ describe('Passwordless landing tests', function () {
             wrapperProps: {
                 siteAlias: 'uk',
                 locale: {id: 'en-GB'},
-                appConfig: mockConfig.app
+                config: mockConfig
             }
         })
 
diff --git a/packages/extension-chakra-storefront/src/pages/reset-password/index.jsx b/packages/extension-chakra-storefront/src/pages/reset-password/index.jsx
index 7180ebc3b0..6b985831cb 100644
--- a/packages/extension-chakra-storefront/src/pages/reset-password/index.jsx
+++ b/packages/extension-chakra-storefront/src/pages/reset-password/index.jsx
@@ -16,14 +16,11 @@ import ResetPasswordLanding from '../../pages/reset-password/reset-password-land
 import useNavigation from '../../hooks/use-navigation'
 import useEinstein from '../../hooks/use-einstein'
 import useDataCloud from '../../hooks/use-datacloud'
-import {useLocation} from 'react-router-dom'
-import {useRouteMatch} from 'react-router'
+import {useLocation, useRouteMatch} from 'react-router-dom'
 import {usePasswordReset} from '../../hooks/use-password-reset'
-import {
-    RESET_PASSWORD_LANDING_PATH,
-    API_ERROR_MESSAGE,
-    FEATURE_UNAVAILABLE_ERROR_MESSAGE
-} from '../../constants'
+import {useExtensionConfig} from '../../hooks'
+
+import {API_ERROR_MESSAGE, FEATURE_UNAVAILABLE_ERROR_MESSAGE} from '../../constants'
 
 const ResetPassword = () => {
     const {formatMessage} = useIntl()
@@ -34,6 +31,7 @@ const ResetPassword = () => {
     const {pathname} = useLocation()
     const {path} = useRouteMatch()
     const {getPasswordResetToken} = usePasswordReset()
+    const {login: loginConfig} = useExtensionConfig()
 
     const submitForm = async ({email}) => {
         try {
@@ -65,7 +63,7 @@ const ResetPassword = () => {
                 marginBottom={8}
                 borderRadius="base"
             >
-                {path === RESET_PASSWORD_LANDING_PATH ? (
+                {path === loginConfig.resetPassword.landingPath ? (
                     <ResetPasswordLanding />
                 ) : (
                     <ResetPasswordForm
diff --git a/packages/extension-chakra-storefront/src/setup-app.tsx b/packages/extension-chakra-storefront/src/setup-app.tsx
index 9d8c91c180..c3af6796b3 100644
--- a/packages/extension-chakra-storefront/src/setup-app.tsx
+++ b/packages/extension-chakra-storefront/src/setup-app.tsx
@@ -62,7 +62,10 @@ class ChakraStorefront extends ApplicationExtension<Config> {
                 exact: true
             },
             {
-                path: config.pages.Login && config.pages.Login.path,
+                path: [
+                    config.pages.Login && config.pages.Login.path,
+                    config.login.passwordless.enabled && config.login.passwordless.landingPath
+                ].filter(Boolean),
                 component: Pages.Login,
                 exact: true
             },
@@ -72,20 +75,13 @@ class ChakraStorefront extends ApplicationExtension<Config> {
                 exact: true
             },
             {
-                path: config.pages.ResetPassword && config.pages.ResetPassword.path,
+                path: [
+                    config.pages.ResetPassword && config.pages.ResetPassword.path,
+                    config.login.resetPassword && config.login.resetPassword.landingPath
+                ].filter(Boolean),
                 component: Pages.ResetPassword,
                 exact: true
             },
-            {
-                path: config.pages.ResetPasswordLanding,
-                component: Pages.ResetPassword,
-                exact: true
-            },
-            {
-                path: config.pages.PasswordlessLoginLanding,
-                component: Pages.Login,
-                exact: true
-            },
             {
                 path: config.pages.Account && config.pages.Account.path,
                 component: Pages.Account
@@ -105,7 +101,7 @@ class ChakraStorefront extends ApplicationExtension<Config> {
                 exact: true
             },
             {
-                path: config.pages.SocialRedirect,
+                path: config.login.social.enabled && config.login.social.redirectURI,
                 component: Pages.SocialLoginRedirect,
                 exact: true
             },
@@ -121,10 +117,6 @@ class ChakraStorefront extends ApplicationExtension<Config> {
             {
                 path: config.pages.ProductList && config.pages.ProductList.path,
                 component: Pages.ProductList
-            },
-            {
-                path: config.pages.WishList,
-                component: Pages.Wishlist
             }
         ].filter((route) => route.path !== false)
 
diff --git a/packages/extension-chakra-storefront/src/setup-server.ts b/packages/extension-chakra-storefront/src/setup-server.ts
index e2038d396e..b8c9142334 100644
--- a/packages/extension-chakra-storefront/src/setup-server.ts
+++ b/packages/extension-chakra-storefront/src/setup-server.ts
@@ -7,6 +7,7 @@
 
 // Third-Party Imports
 import {Application} from 'express'
+import express from 'express'
 import helmet from 'helmet'
 
 // Platform Imports
@@ -16,9 +17,20 @@ import {defaultPwaKitSecurityHeaders} from '@salesforce/pwa-kit-runtime/utils/mi
 // Local Imports
 import {Config} from './types'
 import extensionMeta from '../extension-meta.json'
+import {jwksCachingMiddleware, passwordlessMiddleware, passwordResetMiddleware} from './middleware'
 class RetailReactAppExtension extends ApplicationExtension<Config> {
     static readonly id = extensionMeta.id
     extendApp(app: Application): Application {
+        const config = this.getConfig()
+        const {passwordless: passwordlessConfig, resetPassword: resetPasswordConfig} =
+            config?.login || {}
+        const {commerceAPI: commerceAPIConfig} = config
+
+        const {shortCode} = commerceAPIConfig?.parameters || {}
+        const tenantId = commerceAPIConfig?.parameters?.organizationId?.replace(/^f_ecom_/, '')
+
+        app.use(express.json()) // To parse JSON payloads
+        app.use(express.urlencoded({extended: true}))
         // Set default HTTP security headers required by PWA Kit
         app.use(defaultPwaKitSecurityHeaders)
         // Set custom HTTP security headers
@@ -37,13 +49,37 @@ class RetailReactAppExtension extends ApplicationExtension<Config> {
                         ],
                         'connect-src': [
                             // Connect to Einstein APIs
-                            'api.cquotient.com'
+                            'api.cquotient.com',
+                            // Connect to DataCloud APIs
+                            '*.c360a.salesforce.com'
                         ]
                     }
                 }
             })
         )
 
+        app.use(jwksCachingMiddleware())
+
+        // Apply middleware passwordless.
+        app.use(
+            passwordlessMiddleware({
+                callbackURI: passwordlessConfig?.callbackURI,
+                landingPath: passwordlessConfig?.landingPath,
+                shortCode,
+                tenantId
+            })
+        )
+
+        // Apply middleware password reset.
+        app.use(
+            passwordResetMiddleware({
+                callbackURI: resetPasswordConfig?.callbackURI,
+                landingPath: resetPasswordConfig?.landingPath,
+                shortCode,
+                tenantId
+            })
+        )
+
         // Handle the redirect from SLAS as to avoid error
         app.get('/callback?*', (req, res) => {
             // This endpoint does nothing and is not expected to change
diff --git a/packages/extension-chakra-storefront/src/ssr.js b/packages/extension-chakra-storefront/src/ssr.js
deleted file mode 100644
index 52833a15cb..0000000000
--- a/packages/extension-chakra-storefront/src/ssr.js
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (c) 2023, Salesforce, Inc.
- * All rights reserved.
- * SPDX-License-Identifier: BSD-3-Clause
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
- */
-
-/*
- * Developer note! When updating this file, make sure to also update the
- * ssr.js template files in pwa-kit-create-app.
- *
- * In the pwa-kit-create-app, the templates are found under:
- * - assets/bootstrap/js/overrides/app/ssr.js.hbs
- * - assets/templates/@salesforce/retail-react-app/app/ssr.js.hbs
- */
-
-'use strict'
-
-import crypto from 'crypto'
-import express from 'express'
-import helmet from 'helmet'
-import {createRemoteJWKSet as joseCreateRemoteJWKSet, jwtVerify, decodeJwt} from 'jose'
-import path from 'path'
-import {getRuntime} from '@salesforce/pwa-kit-runtime/ssr/server/express'
-import {defaultPwaKitSecurityHeaders} from '@salesforce/pwa-kit-runtime/utils/middleware'
-import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
-import {getAppOrigin} from '@salesforce/pwa-kit-react-sdk/utils/url'
-
-const config = getConfig()
-
-const options = {
-    // The build directory (an absolute path)
-    buildDir: path.resolve(process.cwd(), 'build'),
-
-    // The cache time for SSR'd pages (defaults to 600 seconds)
-    defaultCacheTimeSeconds: 600,
-
-    // The contents of the config file for the current environment
-    mobify: config,
-
-    // The port that the local dev server listens on
-    port: 3000,
-
-    // The protocol on which the development Express app listens.
-    // Note that http://localhost is treated as a secure context for development,
-    // except by Safari.
-    protocol: 'http',
-
-    // Option for whether to set up a special endpoint for handling
-    // private SLAS clients
-    // Set this to false if using a SLAS public client
-    // When setting this to true, make sure to also set the PWA_KIT_SLAS_CLIENT_SECRET
-    // environment variable as this endpoint will return HTTP 501 if it is not set
-    useSLASPrivateClient: false,
-
-    // If you wish to use additional SLAS endpoints that require private clients,
-    // customize this regex to include the additional endpoints the custom SLAS
-    // private client secret handler will inject an Authorization header.
-    // The default regex is defined in this file: https://github.com/SalesforceCommerceCloud/pwa-kit/blob/develop/packages/pwa-kit-runtime/src/ssr/server/build-remote-server.js
-    // applySLASPrivateClientToEndpoints:
-    //     /\/oauth2\/(token|passwordless\/(login|token)|password\/(reset|action))/,
-
-    // If this is enabled, any HTTP header that has a non ASCII value will be URI encoded
-    // If there any HTTP headers that have been encoded, an additional header will be
-    // passed, `x-encoded-headers`, containing a comma separated list
-    // of the keys of headers that have been encoded
-    // There may be a slight performance loss with requests/responses with large number
-    // of headers as we loop through all the headers to verify ASCII vs non ASCII
-    encodeNonAsciiHttpHeaders: true
-}
-
-const runtime = getRuntime()
-
-/**
- * Tokens are valid for 20 minutes. We store it at the top level scope to reuse
- * it during the lambda invocation. We'll refresh it after 15 minutes.
- */
-let marketingCloudToken = ''
-let marketingCloudTokenExpiration = new Date()
-
-/**
- * Generates a unique ID for the email message.
- *
- * @return {string} A unique ID for the email message.
- */
-function generateUniqueId() {
-    return crypto.randomBytes(16).toString('hex')
-}
-
-/**
- * Sends an email to a specified contact using the Marketing Cloud API. The template email must have a
- * `%%magic-link%%` personalization string inserted.
- * https://help.salesforce.com/s/articleView?id=mktg.mc_es_personalization_strings.htm&type=5
- *
- * @param {string} email - The email address of the contact to whom the email will be sent.
- * @param {string} templateId - The ID of the email template to be used for the email.
- * @param {string} magicLink - The magic link to be included in the email.
- *
- * @return {Promise<object>} A promise that resolves to the response object received from the Marketing Cloud API.
- */
-async function sendMarketingCloudEmail(emailId, marketingCloudConfig) {
-    // Refresh token if expired
-    if (new Date() > marketingCloudTokenExpiration) {
-        const {clientId, clientSecret, subdomain} = marketingCloudConfig
-        const tokenUrl = `https://${subdomain}.auth.marketingcloudapis.com/v2/token`
-        const tokenResponse = await fetch(tokenUrl, {
-            method: 'POST',
-            headers: {'Content-Type': 'application/json'},
-            body: JSON.stringify({
-                grant_type: 'client_credentials',
-                client_id: clientId,
-                client_secret: clientSecret
-            })
-        })
-
-        if (!tokenResponse.ok)
-            throw new Error(
-                'Failed to fetch Marketing Cloud access token. Check your Marketing Cloud credentials and try again.'
-            )
-
-        const {access_token} = await tokenResponse.json()
-        marketingCloudToken = access_token
-        // Set expiration to 15 mins
-        marketingCloudTokenExpiration = new Date(Date.now() + 15 * 60 * 1000)
-    }
-
-    // Send the email
-    const emailUrl = `https://${
-        marketingCloudConfig.subdomain
-    }.rest.marketingcloudapis.com/messaging/v1/email/messages/${generateUniqueId()}`
-    const emailResponse = await fetch(emailUrl, {
-        method: 'POST',
-        headers: {
-            Authorization: `Bearer ${marketingCloudToken}`,
-            'Content-Type': 'application/json'
-        },
-        body: JSON.stringify({
-            definitionKey: marketingCloudConfig.templateId,
-            recipient: {
-                contactKey: emailId,
-                to: emailId,
-                attributes: {'magic-link': marketingCloudConfig.magicLink}
-            }
-        })
-    })
-
-    if (!emailResponse.ok) throw new Error('Failed to send email to Marketing Cloud')
-
-    return await emailResponse.json()
-}
-
-/**
- * Generates a unique ID, constructs an email message URL, and sends the email to the specified contact
- * using the Marketing Cloud API.
- *
- * @param {string} email - The email address of the contact to whom the email will be sent.
- * @param {string} templateId - The ID of the email template to be used for the email.
- * @param {string} magicLink - The magic link to be included in the email.
- *
- * @return {Promise<object>} A promise that resolves to the response object received from the Marketing Cloud API.
- */
-export async function emailLink(emailId, templateId, magicLink) {
-    if (!process.env.MARKETING_CLOUD_CLIENT_ID) {
-        console.warn('MARKETING_CLOUD_CLIENT_ID is not set in the environment variables.')
-    }
-
-    if (!process.env.MARKETING_CLOUD_CLIENT_SECRET) {
-        console.warn(' MARKETING_CLOUD_CLIENT_SECRET is not set in the environment variables.')
-    }
-
-    if (!process.env.MARKETING_CLOUD_SUBDOMAIN) {
-        console.warn('MARKETING_CLOUD_SUBDOMAIN is not set in the environment variables.')
-    }
-
-    const marketingCloudConfig = {
-        clientId: process.env.MARKETING_CLOUD_CLIENT_ID,
-        clientSecret: process.env.MARKETING_CLOUD_CLIENT_SECRET,
-        magicLink: magicLink,
-        subdomain: process.env.MARKETING_CLOUD_SUBDOMAIN,
-        templateId: templateId
-    }
-    return await sendMarketingCloudEmail(emailId, marketingCloudConfig)
-}
-
-const resetPasswordCallback =
-    config.app.login?.resetPassword?.callbackURI || '/reset-password-callback'
-const passwordlessLoginCallback =
-    config.app.login?.passwordless?.callbackURI || '/passwordless-login-callback'
-
-// Reusable function to handle sending a magic link email.
-// By default, this implementation uses Marketing Cloud.
-async function sendMagicLinkEmail(req, res, landingPath, emailTemplate, redirectUrl) {
-    // Extract the base URL from the request
-    const base = req.protocol + '://' + req.get('host')
-
-    // Extract the email_id and token from the request body
-    const {email_id, token} = req.body
-
-    // Construct the magic link URL
-    let magicLink = `${base}${landingPath}?token=${encodeURIComponent(token)}`
-    if (landingPath === config.app.login?.resetPassword?.landingPath) {
-        // Add email query parameter for reset password flow
-        magicLink += `&email=${encodeURIComponent(email_id)}`
-    }
-    if (landingPath === config.app.login?.passwordless?.landingPath && redirectUrl) {
-        magicLink += `&redirect_url=${encodeURIComponent(redirectUrl)}`
-    }
-
-    // Call the emailLink function to send an email with the magic link using Marketing Cloud
-    const emailLinkResponse = await emailLink(email_id, emailTemplate, magicLink)
-
-    // Send the response
-    res.send(emailLinkResponse)
-}
-
-const CLAIM = {
-    ISSUER: 'iss'
-}
-
-const DELIMITER = {
-    ISSUER: '/'
-}
-
-const throwSlasTokenValidationError = (message, code) => {
-    throw new Error(`SLAS Token Validation Error: ${message}`, code)
-}
-
-export const createRemoteJWKSet = (tenantId) => {
-    const appOrigin = getAppOrigin()
-    const {app: appConfig} = getConfig()
-    const shortCode = appConfig.commerceAPI.parameters.shortCode
-    const configTenantId = appConfig.commerceAPI.parameters.organizationId.replace(/^f_ecom_/, '')
-    if (tenantId !== configTenantId) {
-        throw new Error(
-            `The tenant ID in your PWA Kit configuration ("${configTenantId}") does not match the tenant ID in the SLAS callback token ("${tenantId}").`
-        )
-    }
-    const JWKS_URI = `${appOrigin}/${shortCode}/${tenantId}/oauth2/jwks`
-    return joseCreateRemoteJWKSet(new URL(JWKS_URI))
-}
-
-export const validateSlasCallbackToken = async (token) => {
-    const payload = decodeJwt(token)
-    const subClaim = payload[CLAIM.ISSUER]
-    const tokens = subClaim.split(DELIMITER.ISSUER)
-    const tenantId = tokens[2]
-    try {
-        const jwks = createRemoteJWKSet(tenantId)
-        const {payload} = await jwtVerify(token, jwks, {})
-        return payload
-    } catch (error) {
-        throwSlasTokenValidationError(error.message, 401)
-    }
-}
-
-const tenantIdRegExp = /^[a-zA-Z]{4}_([0-9]{3}|s[0-9]{2}|stg|dev|prd)$/
-const shortCodeRegExp = /^[a-zA-Z0-9-]+$/
-
-/**
- *  Handles JWKS (JSON Web Key Set) caching the JWKS response for 2 weeks.
- *
- * @param {object} req Express request object.
- * @param {object} res Express response object.
- * @param {object} options Options for fetching B2C Commerce API JWKS.
- * @param {string} options.shortCode - The Short Code assigned to the realm.
- * @param {string} options.tenantId - The Tenant ID for the ECOM instance.
- * @returns {Promise<*>} Promise with the JWKS data.
- */
-export async function jwksCaching(req, res, options) {
-    const {shortCode, tenantId} = options
-
-    const isValidRequest = tenantIdRegExp.test(tenantId) && shortCodeRegExp.test(shortCode)
-    if (!isValidRequest)
-        return res
-            .status(400)
-            .json({error: 'Bad request parameters: Tenant ID or short code is invalid.'})
-    try {
-        const JWKS_URI = `https://${shortCode}.api.commercecloud.salesforce.com/shopper/auth/v1/organizations/f_ecom_${tenantId}/oauth2/jwks`
-        const response = await fetch(JWKS_URI)
-
-        if (!response.ok) {
-            throw new Error('Request failed with status: ' + response.status)
-        }
-
-        // JWKS rotate every 30 days. For now, cache response for 14 days so that
-        // fetches only need to happen twice a month
-        res.set('Cache-Control', 'public, max-age=1209600, stale-while-revalidate=86400')
-
-        return res.json(await response.json())
-    } catch (error) {
-        res.status(400).json({error: `Error while fetching data: ${error.message}`})
-    }
-}
-
-const {handler} = runtime.createHandler(options, (app) => {
-    app.use(express.json()) // To parse JSON payloads
-    app.use(express.urlencoded({extended: true}))
-    // Set default HTTP security headers required by PWA Kit
-    app.use(defaultPwaKitSecurityHeaders)
-    // Set custom HTTP security headers
-    app.use(
-        helmet({
-            contentSecurityPolicy: {
-                useDefaults: true,
-                directives: {
-                    'img-src': [
-                        // Default source for product images - replace with your CDN
-                        '*.commercecloud.salesforce.com'
-                    ],
-                    'script-src': [
-                        // Used by the service worker in /worker/main.js
-                        'storage.googleapis.com'
-                    ],
-                    'connect-src': [
-                        // Connect to Einstein APIs
-                        'api.cquotient.com',
-                        // Connect to DataCloud APIs
-                        '*.c360a.salesforce.com'
-                    ]
-                }
-            }
-        })
-    )
-
-    // Handle the redirect from SLAS as to avoid error
-    app.get('/callback?*', (req, res) => {
-        // This endpoint does nothing and is not expected to change
-        // Thus we cache it for a year to maximize performance
-        res.set('Cache-Control', `max-age=31536000`)
-        res.send()
-    })
-
-    app.get('/:shortCode/:tenantId/oauth2/jwks', (req, res) => {
-        jwksCaching(req, res, {shortCode: req.params.shortCode, tenantId: req.params.tenantId})
-    })
-
-    // Handles the passwordless login callback route. SLAS makes a POST request to this
-    // endpoint sending the email address and passwordless token. Then this endpoint calls
-    // the sendMagicLinkEmail function to send an email with the passwordless login magic link.
-    // https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas-passwordless-login.html#receive-the-callback
-    app.post(passwordlessLoginCallback, (req, res) => {
-        const slasCallbackToken = req.headers['x-slas-callback-token']
-        const redirectUrl = req.query.redirectUrl
-        validateSlasCallbackToken(slasCallbackToken).then(() => {
-            sendMagicLinkEmail(
-                req,
-                res,
-                config.app.login?.passwordless?.landingPath,
-                process.env.MARKETING_CLOUD_PASSWORDLESS_LOGIN_TEMPLATE,
-                redirectUrl
-            )
-        })
-    })
-
-    // Handles the reset password callback route. SLAS makes a POST request to this
-    // endpoint sending the email address and reset password token. Then this endpoint calls
-    // the sendMagicLinkEmail function to send an email with the reset password magic link.
-    // https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas-password-reset.html#slas-password-reset-flow
-    app.post(resetPasswordCallback, (req, res) => {
-        const slasCallbackToken = req.headers['x-slas-callback-token']
-        validateSlasCallbackToken(slasCallbackToken).then(() => {
-            sendMagicLinkEmail(
-                req,
-                res,
-                config.app.login?.resetPassword?.landingPath,
-                process.env.MARKETING_CLOUD_RESET_PASSWORD_TEMPLATE
-            )
-        })
-    })
-
-    app.get('/robots.txt', runtime.serveStaticFile('static/robots.txt'))
-    app.get('/favicon.ico', runtime.serveStaticFile('static/ico/favicon.ico'))
-
-    app.get('/worker.js(.map)?', runtime.serveServiceWorker)
-    app.get('*', runtime.render)
-})
-// SSR requires that we export a single handler function called 'get', that
-// supports AWS use of the server that we created above.
-export const get = handler
diff --git a/packages/extension-chakra-storefront/src/utils/email.js b/packages/extension-chakra-storefront/src/utils/email.js
new file mode 100644
index 0000000000..6ab2d89138
--- /dev/null
+++ b/packages/extension-chakra-storefront/src/utils/email.js
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2025, salesforce.com, inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+
+import crypto from 'crypto'
+
+/**
+ * Tokens are valid for 20 minutes. We store it at the top level scope to reuse
+ * it during the lambda invocation. We'll refresh it after 15 minutes.
+ */
+let marketingCloudToken = ''
+let marketingCloudTokenExpiration = new Date()
+
+/**
+ * Generates a unique ID for the email message.
+ *
+ * @return {string} A unique ID for the email message.
+ */
+function generateUniqueId() {
+    return crypto.randomBytes(16).toString('hex')
+}
+
+/**
+ * Generates a unique ID, constructs an email message URL, and sends the email to the specified contact
+ * using the Marketing Cloud API.
+ *
+ * @param {string} email - The email address of the contact to whom the email will be sent.
+ * @param {string} templateId - The ID of the email template to be used for the email.
+ * @param {string} magicLink - The magic link to be included in the email.
+ *
+ * @return {Promise<object>} A promise that resolves to the response object received from the Marketing Cloud API.
+ */
+export const emailLink = async (emailId, templateId, magicLink) => {
+    if (!templateId) {
+        throw new Error('templateId is required')
+    }
+
+    if (!process.env.MARKETING_CLOUD_CLIENT_ID) {
+        console.warn('MARKETING_CLOUD_CLIENT_ID is not set in the environment variables.')
+    }
+
+    if (!process.env.MARKETING_CLOUD_CLIENT_SECRET) {
+        console.warn(' MARKETING_CLOUD_CLIENT_SECRET is not set in the environment variables.')
+    }
+
+    if (!process.env.MARKETING_CLOUD_SUBDOMAIN) {
+        console.warn('MARKETING_CLOUD_SUBDOMAIN is not set in the environment variables.')
+    }
+
+    const marketingCloudConfig = {
+        clientId: process.env.MARKETING_CLOUD_CLIENT_ID,
+        clientSecret: process.env.MARKETING_CLOUD_CLIENT_SECRET,
+        magicLink: magicLink,
+        subdomain: process.env.MARKETING_CLOUD_SUBDOMAIN,
+        templateId: templateId
+    }
+    return await sendMarketingCloudEmail(emailId, marketingCloudConfig)
+}
+
+/**
+ * Sends an email to a specified contact using the Marketing Cloud API. The template email must have a
+ * `%%magic-link%%` personalization string inserted.
+ * https://help.salesforce.com/s/articleView?id=mktg.mc_es_personalization_strings.htm&type=5
+ *
+ * @param {string} email - The email address of the contact to whom the email will be sent.
+ * @param {string} templateId - The ID of the email template to be used for the email.
+ * @param {string} magicLink - The magic link to be included in the email.
+ *
+ * @return {Promise<object>} A promise that resolves to the response object received from the Marketing Cloud API.
+ */
+export const sendMarketingCloudEmail = async (emailId, marketingCloudConfig) => {
+    // Refresh token if expired
+    if (new Date() > marketingCloudTokenExpiration) {
+        const {clientId, clientSecret, subdomain} = marketingCloudConfig
+        const tokenUrl = `https://${subdomain}.auth.marketingcloudapis.com/v2/token`
+        const tokenResponse = await fetch(tokenUrl, {
+            method: 'POST',
+            headers: {'Content-Type': 'application/json'},
+            body: JSON.stringify({
+                grant_type: 'client_credentials',
+                client_id: clientId,
+                client_secret: clientSecret
+            })
+        })
+
+        if (!tokenResponse.ok)
+            throw new Error(
+                'Failed to fetch Marketing Cloud access token. Check your Marketing Cloud credentials and try again.'
+            )
+
+        const {access_token} = await tokenResponse.json()
+        marketingCloudToken = access_token
+        // Set expiration to 15 mins
+        marketingCloudTokenExpiration = new Date(Date.now() + 15 * 60 * 1000)
+    }
+
+    // Send the email
+    const emailUrl = `https://${
+        marketingCloudConfig.subdomain
+    }.rest.marketingcloudapis.com/messaging/v1/email/messages/${generateUniqueId()}`
+    const emailResponse = await fetch(emailUrl, {
+        method: 'POST',
+        headers: {
+            Authorization: `Bearer ${marketingCloudToken}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({
+            definitionKey: marketingCloudConfig.templateId,
+            recipient: {
+                contactKey: emailId,
+                to: emailId,
+                attributes: {'magic-link': marketingCloudConfig.magicLink}
+            }
+        })
+    })
+
+    if (!emailResponse.ok) throw new Error('Failed to send email to Marketing Cloud')
+
+    return await emailResponse.json()
+}
diff --git a/packages/extension-chakra-storefront/src/utils/slas.js b/packages/extension-chakra-storefront/src/utils/slas.js
new file mode 100644
index 0000000000..09403c2cd4
--- /dev/null
+++ b/packages/extension-chakra-storefront/src/utils/slas.js
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2025, salesforce.com, inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+
+import {getAppOrigin} from '@salesforce/pwa-kit-react-sdk/utils/url'
+
+import {createRemoteJWKSet as joseCreateRemoteJWKSet, jwtVerify, decodeJwt} from 'jose'
+
+const CLAIM = {
+    ISSUER: 'iss'
+}
+
+const DELIMITER = {
+    ISSUER: '/'
+}
+
+/**
+ * Throws a standardized error for SLAS token validation failures.
+ *
+ * @param {string} message - The error message describing the validation failure.
+ * @param {number} code - The HTTP status code associated with the error.
+ * @throws {Error} Always throws an error with the provided message and code.
+ */
+const throwSlasTokenValidationError = (message, code) => {
+    throw new Error(`SLAS Token Validation Error: ${message}`, code)
+}
+
+/**
+ * Creates a remote JSON Web Key Set (JWKS) URL for verifying JWTs.
+ *
+ * @param {string} tenantId - The tenant ID for the authentication request.
+ * @param {string} shortCode - The short code for the Salesforce instance.
+ * @returns {Function} A function that fetches and caches JWKS for JWT verification.
+ */
+export const createRemoteJWKSet = (tenantId, shortCode) => {
+    const appOrigin = getAppOrigin()
+    const JWKS_URI = `${appOrigin}/${shortCode}/${tenantId}/oauth2/jwks`
+
+    return joseCreateRemoteJWKSet(new URL(JWKS_URI))
+}
+
+/**
+ * Validates a SLAS (Salesforce Login and Authentication Service) callback token.
+ *
+ * @param {string} token - The JWT token to be validated.
+ * @param {string} shortCode - The short code for the Salesforce instance.
+ * @param {string} tenantId - The expected tenant ID for validation.
+ * @returns {Promise<Object>} Resolves with the decoded JWT payload if valid.
+ * @throws {Error} If the tenant ID does not match or the token is invalid.
+ */
+export const validateSlasCallbackToken = async (token, shortCode, tenantId) => {
+    const payload = decodeJwt(token)
+    const subClaim = payload[CLAIM.ISSUER]
+    const tokens = subClaim.split(DELIMITER.ISSUER)
+    const parsedTenantId = tokens[2]
+
+    // If a configuration object is provided, validate the tenant ID against the configured tenant ID.
+    if (parsedTenantId !== tenantId) {
+        throw new Error(
+            `The tenant ID in your PWA Kit configuration ("${tenantId}") does not match the tenant ID in the SLAS callback token ("${tenantId}").`
+        )
+    }
+
+    try {
+        const jwks = createRemoteJWKSet(tenantId, shortCode)
+        const {payload} = await jwtVerify(token, jwks, {})
+        return payload
+    } catch (error) {
+        throwSlasTokenValidationError(error.message, 401)
+    }
+}


Reviews:
user: login: vmarta
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T18:07:37Z
user: login: adamraya
body: Are we expecting this warning in the terminal when running a generated project locally and loading the home page?

```
Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.
    at AuthModal (/Users/arayanavarro/git/v3-pwa-kit/test/build/main-server.js:72661:7)
    at WrappedComponent (/Users/arayanavarro/git/v3-pwa-kit/test/build/main-server.js:71215:9)
```
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T22:19:12Z
user: login: adamraya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T22:38:31Z
user: login: adamraya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T22:46:22Z
user: login: adamraya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T22:46:31Z
user: login: bendvc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T15:57:27Z
user: login: bendvc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T15:58:14Z
user: login: adamraya
body: +1 LGTM

Although, for future improvement I ran into this error by accidentally clicking twice the Google SSO button. Perhaps one solution is to disable the login buttons after click to avoid this issue.

```
{
  "status_code" : "409 CONFLICT",
  "message" : "Tenant id zzrf_001 has already performed a authorize request for usid 053c37ed-b28c-4d58-87ed-a3c49622eda2 in the last 1 seconds."
}
```
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T23:33:34Z
user: login: vmarta
body: Cool, that Checkout bug is fixed now 👍 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T17:27:12Z

Review comments:
diff_hunk: @@ -96,9 +96,6 @@
         },
         "SocialRedirect": {
             "path": "/social-redirect"
-        },
-        "WishList": {
-            "path": "/account/wishlist"
path: packages/extension-chakra-storefront/config/default.json
user: login: vmarta
body: Oh right, this wishlist route will never be matched because of the `/account` route above 👍 
created_at: 2025-04-01T01:15:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -55,7 +55,7 @@ module.exports = {
             landingPath: '/passwordless-login-landing'
         },
         social: {
-            enabled: false,
+            enabled: true,
path: packages/extension-chakra-storefront/src/mock-config.js
user: login: vmarta
body: If we enable this, should we enable passwordless too (on line 53 above)?
created_at: 2025-04-01T01:18:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -72,20 +75,13 @@ class ChakraStorefront extends ApplicationExtension<Config> {
                 exact: true
             },
             {
-                path: config.pages.ResetPassword && config.pages.ResetPassword.path,
+                path: [
+                    config.pages.ResetPassword && config.pages.ResetPassword.path,
+                    config.login.resetPassword && config.login.resetPassword.landingPath
+                ].filter(Boolean),
                 component: Pages.ResetPassword,
                 exact: true
             },
-            {
-                path: config.pages.ResetPasswordLanding,
path: packages/extension-chakra-storefront/src/setup-app.tsx
user: login: vmarta
body: I see that we're combining routes here because they're pointing to the same page component 👍 
created_at: 2025-04-01T17:39:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+import {validateSlasCallbackToken} from '../utils/slas'
+import {emailLink} from '../utils/email'
+
+interface PasswordlessOptions {
+    callbackURI?: string
+    landingPath?: string
+    shortCode: string
+    tenantId: string
+}
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+const passwordlessMiddleware = (options: PasswordlessOptions) => {
+    const {
+        callbackURI = '/passwordless-login-callback',
+        landingPath = '/passwordless-login-landing',
+        shortCode = '',
+        tenantId = ''
path: packages/extension-chakra-storefront/src/middleware/passwordless.ts
user: login: vmarta
body: These options are required, so we don't need default values for them. 

The other middleware (for password reset) already does it correctly.

```suggestion
        shortCode,
        tenantId
```
created_at: 2025-04-01T18:06:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+
+const tenantIdRegExp = /^[a-zA-Z]{4}_([0-9]{3}|s[0-9]{2}|stg|dev|prd)$/
+const shortCodeRegExp = /^[a-zA-Z0-9-]+$/
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+const jwksCachingMiddleware = () => {
+    const router = Router()
+
+    router.get(
+        '/:shortCode/:tenantId/oauth2/jwks',
+        asyncHandler(async (req: Request, res: Response, next: NextFunction) => {
+            const {shortCode, tenantId} = req.params
+            console.log('shortCode:', shortCode)
+            console.log('tenantId:', tenantId)
+            console.log('res:', res)
+            const isValidRequest = tenantIdRegExp.test(tenantId) && shortCodeRegExp.test(shortCode)
+
+            if (!isValidRequest) {
+                return res
+                    .status(400)
+                    .json({error: 'Bad request parameters: Tenant ID or short code is invalid.'})
+            }
+
+            try {
+                const JWKS_URI = `https://${shortCode}.api.commercecloud.salesforce.com/shopper/auth/v1/organizations/f_ecom_${tenantId}/oauth2/jwks`
+                const response = await fetch(JWKS_URI)
+
+                if (!response.ok) {
+                    throw new Error(`Request failed with status: ${response.status}`)
+                }
+
+                // JWKS rotate every 30 days. Cache response for 14 days
+                res.set('Cache-Control', 'public, max-age=1209600, stale-while-revalidate=86400')
path: packages/extension-chakra-storefront/src/middleware/jwks-caching.ts
user: login: adamraya
body: Nit: Do we want to use constants to define these `CACHE_MAX_AGE` and `STALE_WHILE_REVALIDATE` values?
created_at: 2025-04-01T22:38:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+
+const tenantIdRegExp = /^[a-zA-Z]{4}_([0-9]{3}|s[0-9]{2}|stg|dev|prd)$/
+const shortCodeRegExp = /^[a-zA-Z0-9-]+$/
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+const jwksCachingMiddleware = () => {
+    const router = Router()
+
+    router.get(
+        '/:shortCode/:tenantId/oauth2/jwks',
+        asyncHandler(async (req: Request, res: Response, next: NextFunction) => {
+            const {shortCode, tenantId} = req.params
+            console.log('shortCode:', shortCode)
+            console.log('tenantId:', tenantId)
+            console.log('res:', res)
+            const isValidRequest = tenantIdRegExp.test(tenantId) && shortCodeRegExp.test(shortCode)
+
+            if (!isValidRequest) {
+                return res
+                    .status(400)
+                    .json({error: 'Bad request parameters: Tenant ID or short code is invalid.'})
+            }
+
+            try {
+                const JWKS_URI = `https://${shortCode}.api.commercecloud.salesforce.com/shopper/auth/v1/organizations/f_ecom_${tenantId}/oauth2/jwks`
+                const response = await fetch(JWKS_URI)
+
+                if (!response.ok) {
+                    throw new Error(`Request failed with status: ${response.status}`)
+                }
+
+                // JWKS rotate every 30 days. Cache response for 14 days
+                res.set('Cache-Control', 'public, max-age=1209600, stale-while-revalidate=86400')
+
+                return res.json(await response.json())
+            } catch (error) {
+                next(error) // Pass the error to Express error handling middleware
+            }
+        })
+    )
+
+    // Express error handler
+    // router.use((err: Error, req: Request, res: Response) => {
+    //     res.status(500).json({error: `Internal Server Error: ${err.message}`})
+    // })
path: packages/extension-chakra-storefront/src/middleware/jwks-caching.ts
user: login: adamraya
body: Should we uncomment the error handling code?

Do we want to provide the error message only when running locally?
```
res.status(500).json({
            error: 'Internal Server Error',
            message: process.env.NODE_ENV === 'development' ? err.message : 'Internal Server Error'
        })
```
created_at: 2025-04-01T22:46:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+
+const tenantIdRegExp = /^[a-zA-Z]{4}_([0-9]{3}|s[0-9]{2}|stg|dev|prd)$/
+const shortCodeRegExp = /^[a-zA-Z0-9-]+$/
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+const jwksCachingMiddleware = () => {
+    const router = Router()
+
+    router.get(
+        '/:shortCode/:tenantId/oauth2/jwks',
+        asyncHandler(async (req: Request, res: Response, next: NextFunction) => {
+            const {shortCode, tenantId} = req.params
+            console.log('shortCode:', shortCode)
+            console.log('tenantId:', tenantId)
+            console.log('res:', res)
path: packages/extension-chakra-storefront/src/middleware/jwks-caching.ts
user: login: adamraya
body: Do we still need these logs?
created_at: 2025-04-01T22:46:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+
+const tenantIdRegExp = /^[a-zA-Z]{4}_([0-9]{3}|s[0-9]{2}|stg|dev|prd)$/
+const shortCodeRegExp = /^[a-zA-Z0-9-]+$/
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+const jwksCachingMiddleware = () => {
+    const router = Router()
+
+    router.get(
+        '/:shortCode/:tenantId/oauth2/jwks',
+        asyncHandler(async (req: Request, res: Response, next: NextFunction) => {
+            const {shortCode, tenantId} = req.params
+            console.log('shortCode:', shortCode)
+            console.log('tenantId:', tenantId)
+            console.log('res:', res)
+            const isValidRequest = tenantIdRegExp.test(tenantId) && shortCodeRegExp.test(shortCode)
+
+            if (!isValidRequest) {
+                return res
+                    .status(400)
+                    .json({error: 'Bad request parameters: Tenant ID or short code is invalid.'})
+            }
+
+            try {
+                const JWKS_URI = `https://${shortCode}.api.commercecloud.salesforce.com/shopper/auth/v1/organizations/f_ecom_${tenantId}/oauth2/jwks`
+                const response = await fetch(JWKS_URI)
+
+                if (!response.ok) {
+                    throw new Error(`Request failed with status: ${response.status}`)
+                }
+
+                // JWKS rotate every 30 days. Cache response for 14 days
+                res.set('Cache-Control', 'public, max-age=1209600, stale-while-revalidate=86400')
+
+                return res.json(await response.json())
+            } catch (error) {
+                next(error) // Pass the error to Express error handling middleware
+            }
+        })
+    )
+
+    // Express error handler
+    // router.use((err: Error, req: Request, res: Response) => {
+    //     res.status(500).json({error: `Internal Server Error: ${err.message}`})
+    // })
path: packages/extension-chakra-storefront/src/middleware/jwks-caching.ts
user: login: bendvc
body: I'm honestly not sure that that was from... might have been an artifact of my conversion to a middleware. Don't see a similar use in develop. So unless you know what that is for, then I simply gonna remove it. 
created_at: 2025-04-02T15:57:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, Salesforce, Inc.
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
+ */
+import {Router, Request, Response, NextFunction} from 'express'
+
+const tenantIdRegExp = /^[a-zA-Z]{4}_([0-9]{3}|s[0-9]{2}|stg|dev|prd)$/
+const shortCodeRegExp = /^[a-zA-Z0-9-]+$/
+
+const asyncHandler =
+    (fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) =>
+    (req: Request, res: Response, next: NextFunction) => {
+        Promise.resolve(fn(req, res, next)).catch(next)
+    }
+
+const jwksCachingMiddleware = () => {
+    const router = Router()
+
+    router.get(
+        '/:shortCode/:tenantId/oauth2/jwks',
+        asyncHandler(async (req: Request, res: Response, next: NextFunction) => {
+            const {shortCode, tenantId} = req.params
+            console.log('shortCode:', shortCode)
+            console.log('tenantId:', tenantId)
+            console.log('res:', res)
+            const isValidRequest = tenantIdRegExp.test(tenantId) && shortCodeRegExp.test(shortCode)
+
+            if (!isValidRequest) {
+                return res
+                    .status(400)
+                    .json({error: 'Bad request parameters: Tenant ID or short code is invalid.'})
+            }
+
+            try {
+                const JWKS_URI = `https://${shortCode}.api.commercecloud.salesforce.com/shopper/auth/v1/organizations/f_ecom_${tenantId}/oauth2/jwks`
+                const response = await fetch(JWKS_URI)
+
+                if (!response.ok) {
+                    throw new Error(`Request failed with status: ${response.status}`)
+                }
+
+                // JWKS rotate every 30 days. Cache response for 14 days
+                res.set('Cache-Control', 'public, max-age=1209600, stale-while-revalidate=86400')
path: packages/extension-chakra-storefront/src/middleware/jwks-caching.ts
user: login: bendvc
body: We can do that in a follow up PR, or it's possibly something that we'll end up taking care of once we break down the storefront extension into smaller pieces.
created_at: 2025-04-02T15:58:14Z
author_association: CONTRIBUTOR

PR comments:
user: login: vmarta
created_at: 2025-04-01T00:53:11Z
body: Thanks for the testing instruction.

For the **magic link / passwordless login**, I got a 404 page when I clicked on the link in the email.

The email link has `redirect_url=undefined` in the url param: 
http://scaffold-pwa-bens-playground.mobify-storefront.com/passwordless-login-landing?token=97345422&redirect_url=undefined

Clicking the link above navigates me to the url: https://scaffold-pwa-bens-playground.mobify-storefront.com/global/en-GBundefined → 404 error

Update: here's how to reproduce the issue.
1. Navigate to https://scaffold-pwa-bens-playground.mobify-storefront.com/global/en-GB/login
2. Follow the passwordless flow
3. Check whether the link in your email has `redirect_url=undefined`
author_association: CONTRIBUTOR
user: login: vmarta
created_at: 2025-04-01T01:03:44Z
body: The other features - social login, password reset, and even the normal login with password - are all working as expected.

So yeah, the only thing that's a bit broken is the scenario above for the [passwordless login](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2340#issuecomment-2767749084).
author_association: CONTRIBUTOR
user: login: vmarta
created_at: 2025-04-01T18:23:10Z
body: Checkout page in the deployed testing site only allows you to log in with a password. 

On retail-react-app, we see Checkout having social logins, etc:
![Arc 2025-04-01 at 11 20 03](https://github.com/user-attachments/assets/2a357125-13cd-4536-9257-2891865c27a8)

author_association: CONTRIBUTOR
user: login: bendvc
created_at: 2025-04-01T20:24:08Z
body: > Thanks for the testing instruction.
> 
> For the **magic link / passwordless login**, I got a 404 page when I clicked on the link in the email.
> 
> The email link has `redirect_url=undefined` in the url param: http://scaffold-pwa-bens-playground.mobify-storefront.com/passwordless-login-landing?token=97345422&redirect_url=undefined
> 
> Clicking the link above navigates me to the url: https://scaffold-pwa-bens-playground.mobify-storefront.com/global/en-GBundefined → 404 error
> 
> Update: here's how to reproduce the issue.
> 
> 1. Navigate to https://scaffold-pwa-bens-playground.mobify-storefront.com/global/en-GB/login
> 2. Follow the passwordless flow
> 3. Check whether the link in your email has `redirect_url=undefined`

I have fixed this issue.
author_association: CONTRIBUTOR
user: login: adamraya
created_at: 2025-04-01T22:29:38Z
body: Potentially not related to this PR. But any idea why the header looks different in the checkout page?
https://scaffold-pwa-bens-playground.mobify-storefront.com/global/en-GB/checkout

<img width="1632" alt="Screenshot_2025-04-01_at_3_23_42 PM" src="https://github.com/user-attachments/assets/29fde022-41bb-4f90-a122-fa7c3cf39153" />

author_association: CONTRIBUTOR
user: login: vmarta
created_at: 2025-04-02T17:48:23Z
body: In Checkout, it's possible to run into `undefined` js error. Here's how to reproduce the bug:

1. As a guest shopper, add an item to your cart and check out
2. On the Checkout page, log in with the Secure Link flow
3. Check your email inbox and click on the link to automatically log in
4. Back in your browser, a new tab is opened that shows the Checkout page with you being logged in
5. However, the _original_ tab is refreshed and will show you the following error message:

![Arc 2025-04-02 at 10 39 08](https://github.com/user-attachments/assets/a91b8350-8054-4a15-9bf4-deed57559a08)

(The above issue does _not_ exist in pwa-kit.mobify-storefront.com)
author_association: CONTRIBUTOR
user: login: bendvc
created_at: 2025-04-02T17:50:47Z
body: > Potentially not related to this PR. But any idea why the header looks different in the checkout page? https://scaffold-pwa-bens-playground.mobify-storefront.com/global/en-GB/checkout
> 
> <img alt="Screenshot_2025-04-01_at_3_23_42 PM" width="1632" src="https://private-user-images.githubusercontent.com/6024102/429239808-29fde022-41bb-4f90-a122-fa7c3cf39153.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDM2MTM0NzAsIm5iZiI6MTc0MzYxMzE3MCwicGF0aCI6Ii82MDI0MTAyLzQyOTIzOTgwOC0yOWZkZTAyMi00MWJiLTRmOTAtYTEyMi1mYTdjM2NmMzkxNTMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDQwMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA0MDJUMTY1OTMwWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODExMmZiMjRhYmU2MDI4MDAxODZmOWFhMmQ1ODAyNTg3YTZmZTE3YTg1YjVlN2EwMWRhYzBhYzc2MzAyNGQ5NyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.Jq0MVyehnjochbZCjutzbBfqRQjrCxoUtzsli7umb1w">

Looking at the git history it looks like that was a regression at some point when someone was fixing typescript issues. I have fixed it so that it uses the proper styling for that component. but I had to employ a ts-ignore. I think this will be something that will be addresses when we do all that styling theme cleanup work.
author_association: CONTRIBUTOR
user: login: bendvc
created_at: 2025-04-02T22:41:04Z
body: > In Checkout, it's possible to run into `undefined` js error. Here's how to reproduce the bug:
> 
> 1. As a guest shopper, add an item to your cart and check out
> 2. On the Checkout page, log in with the Secure Link flow
> 3. Check your email inbox and click on the link to automatically log in
> 4. Back in your browser, a new tab is opened that shows the Checkout page with you being logged in
> 5. However, the _original_ tab is refreshed and will show you the following error message:
> 
> ![Arc 2025-04-02 at 10 39 08](https://private-user-images.githubusercontent.com/847300/429602219-a91b8350-8054-4a15-9bf4-deed57559a08.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDM2MzM2NjcsIm5iZiI6MTc0MzYzMzM2NywicGF0aCI6Ii84NDczMDAvNDI5NjAyMjE5LWE5MWI4MzUwLTgwNTQtNGExNS05YmY0LWRlZWQ1NzU1OWEwOC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwNDAyJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDQwMlQyMjM2MDdaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1jZWYwODM3NDNjM2Y4OWJmODgyYmY2MGJjNzIzOTcwNGEyYjllMTZiZmE2YjM3MDIwZmJjYzMwYTNlYmZkYTkxJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.YXV4XL0NqK2_v0X4NDNKk-fVU7vfq90hTCvzWHaGq8Y)
> 
> (The above issue does _not_ exist in pwa-kit.mobify-storefront.com)

I've fixed this at the root where the component was possible accessing a property from an undefined object. I was unable to determine why it isn't happening on the demo site.

I've create a [ticket](https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE00002C5SRIYA3/view) here to add the service working to the typescript minimal project, I didn't want to do that in this pr as its going to raise some other questions and I'd prefer that we don't delay this ticket anymore.
author_association: CONTRIBUTOR