Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Phased Launch] Call Session bridge after login #1220

Merged
merged 7 commits into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion packages/commerce-sdk-react/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface AuthConfig extends ApiClientConfigParams {
proxy: string
fetchOptions?: ShopperLoginTypes.FetchOptions
fetchedToken?: string
OCAPISessionsURL?: string
}

interface JWTHeaders {
Expand Down Expand Up @@ -138,6 +139,7 @@ class Auth {
private REFRESH_TOKEN_EXPIRATION_DAYS = 90
private stores: Record<StorageType, BaseStorage>
private fetchedToken: string
private OCAPISessionsURL: string

constructor(config: AuthConfig) {
this.client = new ShopperLogin({
Expand Down Expand Up @@ -185,6 +187,8 @@ class Auth {
this.redirectURI = config.redirectURI

this.fetchedToken = config.fetchedToken || ''

this.OCAPISessionsURL = config.OCAPISessionsURL || ''
}

get(name: AuthDataKeys) {
Expand Down Expand Up @@ -272,7 +276,9 @@ class Auth {
.then(async () => {
const token = await fn()
this.handleTokenResponse(token, isGuest)

if (onClient() && this.OCAPISessionsURL) {
void this.createOCAPISession()
}
// Q: Why don't we just return token? Why re-construct the same object again?
// A: because a user could open multiple tabs and the data in memory could be out-dated
// We must always grab the data from the storage (cookie/localstorage) directly
Expand Down Expand Up @@ -430,6 +436,26 @@ class Auth {
return this.loginGuestUser()
}

/**
* Make a post request to the OCAPI /session endpoint to bridge the session.
*
* The HTTP response contains a set-cookie header which sets the dwsid session cookie.
* This cookie is used on SFRA, and it allows shoppers to navigate between SFRA and
* this PWA site seamlessly; this is often used to enable hybrid deployment.
*
* (Note: this method is client side only, b/c MRT doesn't support set-cookie header right now)
*
* @returns {Promise}
*/
createOCAPISession() {
return fetch(this.OCAPISessionsURL, {
method: 'POST',
headers: {
Authorization: this.get('access_token')
}
})
}

/**
* Decode SLAS JWT and extract information such as customer id, usid, etc.
*
Expand Down
10 changes: 7 additions & 3 deletions packages/commerce-sdk-react/src/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface CommerceApiProviderProps extends ApiClientConfigParams {
fetchOptions?: ShopperBasketsTypes.FetchOptions
headers?: Record<string, string>
fetchedToken?: string
OCAPISessionsURL?: string
}

/**
Expand Down Expand Up @@ -66,7 +67,8 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => {
shortCode,
locale,
currency,
fetchedToken
fetchedToken,
OCAPISessionsURL
} = props

const config = {
Expand Down Expand Up @@ -117,7 +119,8 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => {
proxy,
redirectURI,
fetchOptions,
fetchedToken
fetchedToken,
OCAPISessionsURL
})
}, [
clientId,
Expand All @@ -127,7 +130,8 @@ const CommerceApiProvider = (props: CommerceApiProviderProps): ReactElement => {
proxy,
redirectURI,
fetchOptions,
fetchedToken
fetchedToken,
OCAPISessionsURL
])

// Initialize the session
Expand Down
3 changes: 2 additions & 1 deletion packages/commerce-sdk-react/src/test-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export const DEFAULT_TEST_CONFIG = {
siteId: 'RefArchGlobal',
locale: 'en-US',
currency: 'USD',
fetchedToken: 'test-token'
fetchedToken: 'test-token',
OCAPISessionsURL: `${DEFAULT_TEST_HOST}/mobify/proxy/ocapi/s/RefArch/dw/shop/v22_8/sessions`
}

export const createQueryClient = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const AppConfig = ({children, locals = {}}) => {
redirectURI={`${appOrigin}/callback`}
proxy={`${appOrigin}${commerceApiConfig.proxyPath}`}
headers={headers}
OCAPISessionsURL={`${appOrigin}/mobify/proxy/ocapi/s/${locals.site?.id}/dw/shop/v22_8/sessions`}
>
<MultiSiteProvider site={locals.site} locale={locals.locale} buildUrl={locals.buildUrl}>
<ChakraProvider theme={theme}>{children}</ChakraProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {registerUserToken} from '../../utils/test-utils'
describe('AppConfig', () => {
beforeAll(() => {
jest.spyOn(window.localStorage, 'setItem')
global.fetch = jest.fn().mockImplementation(() => mockConfig.mockFetchOCAPISessions)
})

beforeEach(() => {
Expand All @@ -43,6 +44,8 @@ describe('AppConfig', () => {

afterAll(() => {
window.localStorage.setItem.mockRestore()
global.fetch.mockClear()
delete global.fetch
})

test('renders', async () => {
Expand Down
9 changes: 9 additions & 0 deletions packages/template-retail-react-app/config/mocks/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,14 @@ module.exports = {
path: 'ocapi'
}
]
},
mockFetchOCAPISessions: (url) => {
if (url.includes('/sessions')) {
return {
ok: true,
status: 200
}
}
throw new Error(`Unhandled request: ${url}`)
}
}