Skip to content

Commit

Permalink
Hybrid session sync fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
shethj committed Oct 4, 2024
1 parent 81ba02f commit ba95ec6
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 15 deletions.
18 changes: 8 additions & 10 deletions packages/template-retail-react-app/app/commerce-api/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
REFRESH_TOKEN_COOKIE_AGE,
EXPIRED_TOKEN,
INVALID_TOKEN,
DWSID_STORAGE_KEY,
EXCLUDE_COOKIE_SUFFIX
} from './constants'
import Cookies from 'js-cookie'
Expand Down Expand Up @@ -51,7 +50,7 @@ class Auth {
this._onClient = typeof window !== 'undefined'

const _options = {
keySuffix: this._config.parameters.siteId,
keySuffix: this._config.parameters.siteId
}

this._cookieStorage = this._onClient ? new CookieStorage(_options) : new Map()
Expand Down Expand Up @@ -97,7 +96,7 @@ class Auth {
}

get userType() {
return this._storage.get(refreshTokenRegisteredStorageKey)
return this._cookieStorage.get(refreshTokenRegisteredStorageKey)
? Auth.USER_TYPE.REGISTERED
: Auth.USER_TYPE.GUEST
}
Expand Down Expand Up @@ -145,7 +144,7 @@ class Auth {
}

get dwsid() {
return this._cookieStorage.get(DWSID_STORAGE_KEY)
return this._cookieStorage.get(dwSessionIdKey)
}

get isTokenValid() {
Expand Down Expand Up @@ -343,7 +342,7 @@ class Auth {
// For Phased Launch storefronts, if the shopper logs into a registered account on PWA Kit,
// dwsid cookie must be cleared to trigger onSession in Plugin SLAS which will then use the new
// registered refresh_token (cc-nx cookie) value to restore SFRA/SG session for registered shopper.
this._cookieStorage.delete(DWSID_STORAGE_KEY)
this._cookieStorage.delete(dwSessionIdKey)

const tokenBody = createGetTokenBody(
response.url,
Expand Down Expand Up @@ -475,13 +474,12 @@ class Auth {
*/
_clearAuth() {
this._storage.delete(tokenStorageKey)
this._storage.delete(refreshTokenRegisteredStorageKey)
this._storage.delete(refreshTokenGuestStorageKey)
this._storage.delete(usidStorageKey)
this._cookieStorage.delete(refreshTokenRegisteredStorageKey)
this._cookieStorage.delete(refreshTokenGuestStorageKey)
this._cookieStorage.delete(usidStorageKey)
this._storage.delete(cidStorageKey)
this._storage.delete(encUserIdStorageKey)
this._storage.delete(dwSessionIdKey)
this._cookieStorage.delete(DWSID_STORAGE_KEY)
this._cookieStorage.delete(dwSessionIdKey)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ export const dwSessionIdKey = 'dwsid'
export const REFRESH_TOKEN_COOKIE_AGE = 90 // 90 days. This value matches SLAS cartridge.
export const EXPIRED_TOKEN = 'EXPIRED_TOKEN'
export const INVALID_TOKEN = 'invalid refresh_token'
export const DWSID_STORAGE_KEY = 'dwsid'
export const ECOM_ACCESS_TOKEN_STORAGE_KEY = 'cc-at'
export const DWSID_SERVER_AFFINITY_HEADER = 'sfdc_dwsid'

// commerce-sdk-react namespaces cookies with siteID as suffixes to allow multisite setups.
// However some cookies are set and used outside of PWA Kit and must not be modified with suffixes.
export const EXCLUDE_COOKIE_SUFFIX = ['dwsid']
export const EXCLUDE_COOKIE_SUFFIX = ['dwsid']
47 changes: 44 additions & 3 deletions packages/template-retail-react-app/app/commerce-api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
import jwtDecode from 'jwt-decode'
import {getAppOrigin} from 'pwa-kit-react-sdk/utils/url'
import {HTTPError} from 'pwa-kit-react-sdk/ssr/universal/errors'
import {ECOM_ACCESS_TOKEN_STORAGE_KEY, tokenStorageKey} from './constants'
import {
cidStorageKey,
ECOM_ACCESS_TOKEN_STORAGE_KEY,
tokenStorageKey,
usidStorageKey
} from './constants'
import fetch from 'cross-fetch'

/**
Expand Down Expand Up @@ -273,6 +278,34 @@ export const convertSnakeCaseToSentenceCase = (text) => {
*/
export const noop = () => {}

/**
* Decode SLAS JWT and extract information such as customer id, usid, etc.
* @param {string} jwt
*/
export function parseSLASJwt(jwt) {
const payload = jwtDecode(jwt)
const {sub, isb} = payload

if (!sub || !isb) {
throw new Error('Unable to parse access token payload: missing sub and isb.')
}

// ISB format
//'uido:ecom::upn:Guest||xxxEmailxxx::uidn:FirstName LastName::gcid:xxxGuestCustomerIdxxx::rcid:xxxRegisteredCustomerIdxxx::chid:xxxSiteIdxxx',
const isbParts = isb.split('::')
const isGuest = isbParts[1] === 'upn:Guest'
const customerId = isGuest ? isbParts[3].replace('gcid:', '') : isbParts[4].replace('rcid:', '')

// Sub format
// cc-slas::zzrf_001::scid:c9c45bfd-0ed3-4aa2-xxxx-40f88962b836::usid:b4865233-de92-4039-xxxx-aa2dfc8c1ea5
const usid = sub.split('::')[3].replace('usid:', '')
return {
isGuest,
customerId,
usid
}
}

/**
* WARNING: This function is relevant to be used in Phased Launch deployments only.
*
Expand Down Expand Up @@ -302,8 +335,16 @@ export function hasSFRAAuthStateChanged(storage, cookieStorage) {
return true
}

// If a cc-at cookie is found and it's value is NOT 'refresh',
// Update localStoreage token cookie to cc-at value and delete cc-at cookie.
/**
* If a cc-at cookie is found and it's value is NOT 'refresh',
* Parse JWT to get customerId and usid and update the values,
* Update localStoreage token cookie to cc-at value and delete cc-at cookie.
*/
const {customerId, usid} = parseSLASJwt(SFRAAuthToken)

storage.set(tokenStorageKey, `Bearer ${SFRAAuthToken}`)
storage.set(cidStorageKey, customerId)
cookieStorage.set(usidStorageKey, usid)
cookieStorage.delete(ECOM_ACCESS_TOKEN_STORAGE_KEY)
return false
}

0 comments on commit ba95ec6

Please sign in to comment.