From f04bd360f676cfe97c69b9fabec312315db2f52e Mon Sep 17 00:00:00 2001 From: Vitor Date: Wed, 16 Sep 2026 16:23:26 -0300 Subject: [PATCH] fix(storefront): Stop sending an expired login to the checkout app Returning customers whose stored token had expired were dropped on the "complete your registration" form as if they were new, and orders created duplicated customers. The legacy app.js trusts any `auth.id` on the `ecomPassportClient` cookie (no expiry check), requests `/customers/:id` with the dead token, gets 401 and logs out without leaving the form. vbeta-app now drops that cookie when the Cloud Commerce session is not authenticated and the cookie was written by it (level 3), keeping legacy e-mail + document identifications untouched. app.js then starts unidentified and receives the `login` event when the token is renewed, either before it loads (#785 wait) or later through `setSession`. Co-Authored-By: Claude Fable 5.1 --- .../storefront/src/lib/scripts/vbeta-app.ts | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/storefront/src/lib/scripts/vbeta-app.ts b/packages/storefront/src/lib/scripts/vbeta-app.ts index d01e1f6ae..396f69a15 100644 --- a/packages/storefront/src/lib/scripts/vbeta-app.ts +++ b/packages/storefront/src/lib/scripts/vbeta-app.ts @@ -263,6 +263,25 @@ if (!import.meta.env.SSR) { (window as any).ECOMCLIENT_API_MODULES = `${hostApiBaseUri}modules/`; const passportStorageKey = 'ecomPassportClient'; + // app.js trusts any `auth.id` on the passport cookie (no token expiry check) and + // requests `/customers/:id` with it: a stale token gets 401, then `logout()`, and + // the buyer is left on the "complete your registration" form as a new customer. + // Level 3 is set only from a Cloud Commerce session, so when that session is not + // authenticated the cookie holds an expired or logged out token: drop it, app.js + // starts unidentified and gets the `login` event once the token is renewed. + const clearStalePassportCookie = () => { + const cookieValue = document.cookie.split('; ') + .find((cookie) => cookie.startsWith(`${passportStorageKey}=`)) + ?.slice(passportStorageKey.length + 1); + if (!cookieValue) return; + try { + const { auth } = JSON.parse(decodeURIComponent(cookieValue)); + if (auth?.level !== 3) return; // legacy e-mail + doc identification, keep it + } catch { + // malformed, drop it anyway + } + setCookie(passportStorageKey, '', -1); + }; watch(isAuthenticated, async () => { const { ecomPassport } = window as Record; if (isAuthenticated.value) { @@ -281,8 +300,12 @@ if (!import.meta.env.SSR) { } else { setCookie(passportStorageKey, JSON.stringify(passportSession)); } - } else if (ecomPassport?.checkLogin()) { - ecomPassport.logout(); + } else if (ecomPassport) { + if (ecomPassport.checkLogin()) { + ecomPassport.logout(); + } + } else { + clearStalePassportCookie(); } }, { immediate: true,