Skip to content

Commit

Permalink
ShopifyCustomerPrivacy fixes and improvements (#2103)
Browse files Browse the repository at this point in the history
* remove setting of id_token during token refresh

* ShopifyCustomerPrivacy improvements

* Prettier

* skeleton-analytics

* Update invalid token log

* Prettier

---------

Co-authored-by: Michelle Chen <michelle.chen@shopify.com>
  • Loading branch information
juanpprieto and michenly committed May 14, 2024
1 parent c4a5972 commit 7def3e9
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 35 deletions.
5 changes: 5 additions & 0 deletions .changeset/unlucky-students-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen': patch
---

Fix: remove setting of `id_token` during Customer Account API token refresh because it does not get return in the API.
65 changes: 40 additions & 25 deletions packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {useLoadScript} from '@shopify/hydrogen-react';
import {useEffect, useRef} from 'react';

export type ConsentStatus = 'true' | 'false' | '';
export type ConsentStatus = boolean | undefined;

export type VisitorConsent = {
marketing: ConsentStatus;
Expand Down Expand Up @@ -96,7 +96,7 @@ const CONSENT_API_WITH_BANNER =
function logMissingConfig(fieldName: string) {
// eslint-disable-next-line no-console
console.error(
`[h2:error:useCustomerPrivacy] Unable to setup Customer Privacy API: Missing consent.${fieldName} consent configuration.`,
`[h2:error:useCustomerPrivacy] Unable to setup Customer Privacy API: Missing consent.${fieldName} configuration.`,
);
}

Expand All @@ -117,10 +117,6 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) {
},
);

if (!consentConfig.checkoutDomain) logMissingConfig('checkoutDomain');
if (!consentConfig.storefrontAccessToken)
logMissingConfig('storefrontAccessToken');

useEffect(() => {
const consentCollectedHandler = (
event: CustomEvent<VisitorConsentCollected>,
Expand All @@ -145,36 +141,55 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) {

useEffect(() => {
if (scriptStatus !== 'done' || loadedEvent.current) return;

loadedEvent.current = true;

if (!consentConfig.checkoutDomain) logMissingConfig('checkoutDomain');
if (!consentConfig.storefrontAccessToken)
logMissingConfig('storefrontAccessToken');

// validate that the storefront access token is not a server API token
if (
consentConfig.storefrontAccessToken.startsWith('shpat_') ||
consentConfig.storefrontAccessToken.length !== 32
) {
// eslint-disable-next-line no-console
console.error(
`[h2:error:useCustomerPrivacy] It looks like you passed a private access token, make sure to use the public token`,
);
console;
}

if (withPrivacyBanner && window?.privacyBanner) {
window?.privacyBanner?.loadBanner({
checkoutRootDomain: consentConfig.checkoutDomain,
storefrontAccessToken: consentConfig.storefrontAccessToken,
});
}

if (!window.Shopify?.customerPrivacy) return;

// Override the setTrackingConsent method to include the headless storefront configuration
if (window.Shopify?.customerPrivacy) {
const originalSetTrackingConsent =
window.Shopify.customerPrivacy.setTrackingConsent;
window.Shopify.customerPrivacy.setTrackingConsent = (
consent: VisitorConsent,
callback: () => void,
) => {
originalSetTrackingConsent(
{
...consent,
headlessStorefront: true,
checkoutRootDomain: consentConfig.checkoutDomain,
storefrontAccessToken: consentConfig.storefrontAccessToken,
},
callback,
);
};
const originalSetTrackingConsent =
window.Shopify.customerPrivacy.setTrackingConsent;

function overrideSetTrackingConsent(
consent: VisitorConsent,
callback: (data: {error: string} | undefined) => void,
) {
originalSetTrackingConsent(
{
...consent,
headlessStorefront: true,
checkoutRootDomain: consentConfig.checkoutDomain,
storefrontAccessToken: consentConfig.storefrontAccessToken,
},
callback,
);
}

window.Shopify.customerPrivacy.setTrackingConsent =
overrideSetTrackingConsent;

if (onReady && !withPrivacyBanner) {
onReady();
}
Expand All @@ -183,7 +198,7 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) {
return;
}

export function getCustomerPrivacy() {
export function getCustomerPrivacy(): CustomerPrivacy | null {
try {
return window.Shopify && window.Shopify.customerPrivacy
? window.Shopify?.customerPrivacy
Expand Down
7 changes: 0 additions & 7 deletions packages/hydrogen/src/customer/auth.helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ describe('auth.helpers', () => {
{
access_token: '',
expires_in: '',
id_token: '',
refresh_token: '',
},
{ok: true},
Expand Down Expand Up @@ -129,7 +128,6 @@ describe('auth.helpers', () => {
{
access_token: 'access_token',
expires_in: '',
id_token: 'id_token',
refresh_token: 'refresh_token',
},
{ok: true},
Expand All @@ -151,7 +149,6 @@ describe('auth.helpers', () => {
accessToken: 'access_token',
expiresAt: expect.any(String),
refreshToken: 'refresh_token',
idToken: 'id_token',
},
);
});
Expand Down Expand Up @@ -217,7 +214,6 @@ describe('auth.helpers', () => {
{
access_token: 'access_token',
expires_in: '',
id_token: 'id_token',
refresh_token: 'refresh_token',
},
{ok: true},
Expand All @@ -241,7 +237,6 @@ describe('auth.helpers', () => {
accessToken: 'access_token',
expiresAt: expect.any(String),
refreshToken: 'refresh_token',
idToken: 'id_token',
},
);
});
Expand All @@ -256,7 +251,6 @@ describe('auth.helpers', () => {
{
access_token: 'access_token',
expires_in: '',
id_token: 'id_token',
refresh_token: 'refresh_token',
},
{ok: true},
Expand All @@ -280,7 +274,6 @@ describe('auth.helpers', () => {
accessToken: 'access_token',
expiresAt: expect.any(String),
refreshToken: 'refresh_token',
idToken: 'id_token',
});
});
});
Expand Down
6 changes: 3 additions & 3 deletions packages/hydrogen/src/customer/auth.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,9 @@ export async function refreshToken({
});
}

const {access_token, expires_in, id_token, refresh_token} =
await response.json<AccessTokenResponse>();
const {access_token, expires_in, refresh_token} = await response.json<
Omit<AccessTokenResponse, 'id_token'>
>();

const accessToken = await exchangeAccessToken(
access_token,
Expand All @@ -146,7 +147,6 @@ export async function refreshToken({
expiresAt:
new Date(new Date().getTime() + (expires_in - 120) * 1000).getTime() + '',
refreshToken: refresh_token,
idToken: id_token,
});

await exchangeForStorefrontCustomerAccessToken();
Expand Down

0 comments on commit 7def3e9

Please sign in to comment.