Skip to content

Commit

Permalink
[BuyerAuthentication] if shopId is passed, use the core url (#2437)
Browse files Browse the repository at this point in the history
Co-authored-by: Michelle Chen <michelle.chen@shopify.com>
Co-authored-by: Helen Lin <helen.lin@shopify.com>
  • Loading branch information
3 people committed Sep 25, 2024
1 parent bb5b097 commit f336303
Show file tree
Hide file tree
Showing 12 changed files with 1,201 additions and 449 deletions.
5 changes: 5 additions & 0 deletions .changeset/rare-drinks-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen': patch
---

Update customer account buyer authentication exchange
3 changes: 2 additions & 1 deletion packages/hydrogen/src/createHydrogenContext.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const mockEnv = {
'PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID_value',
PUBLIC_CUSTOMER_ACCOUNT_API_URL: 'PUBLIC_CUSTOMER_ACCOUNT_API_URL_value',
PUBLIC_CHECKOUT_DOMAIN: 'PUBLIC_CHECKOUT_DOMAIN_value',
SHOP_ID: 'SHOP_ID_value',
};

const defaultOptions = {
Expand Down Expand Up @@ -179,7 +180,7 @@ describe('createHydrogenContext', () => {
expect(vi.mocked(createCustomerAccountClient)).toHaveBeenCalledWith(
expect.objectContaining({
customerAccountId: mockEnv.PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID,
customerAccountUrl: mockEnv.PUBLIC_CUSTOMER_ACCOUNT_API_URL,
shopId: mockEnv.SHOP_ID,
}),
);
});
Expand Down
3 changes: 3 additions & 0 deletions packages/hydrogen/src/createHydrogenContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ export function createHydrogenContext<

// defaults
customerAccountId: env.PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID,
shopId: env.SHOP_ID,

// deprecated - keep until next major release
customerAccountUrl: env.PUBLIC_CUSTOMER_ACCOUNT_API_URL,
});

Expand Down
14 changes: 7 additions & 7 deletions packages/hydrogen/src/customer/auth.helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('auth.helpers', () => {
await refreshToken({
session,
customerAccountId: 'customerAccountId',
customerAccountUrl: 'customerAccountUrl',
customerAccountTokenExchangeUrl: 'customerAccountTokenExchangeUrl',
httpsOrigin: 'https://localhost',
exchangeForStorefrontCustomerAccessToken,
});
Expand All @@ -78,7 +78,7 @@ describe('auth.helpers', () => {
await refreshToken({
session,
customerAccountId: 'customerAccountId',
customerAccountUrl: 'customerAccountUrl',
customerAccountTokenExchangeUrl: 'customerAccountTokenExchangeUrl',
httpsOrigin: 'https://localhost',
exchangeForStorefrontCustomerAccessToken,
});
Expand Down Expand Up @@ -107,7 +107,7 @@ describe('auth.helpers', () => {
await refreshToken({
session,
customerAccountId: 'customerAccountId',
customerAccountUrl: 'customerAccountUrl',
customerAccountTokenExchangeUrl: 'customerAccountTokenExchangeUrl',
httpsOrigin: 'https://localhost',
exchangeForStorefrontCustomerAccessToken,
});
Expand Down Expand Up @@ -138,7 +138,7 @@ describe('auth.helpers', () => {
await refreshToken({
session,
customerAccountId: 'customerAccountId',
customerAccountUrl: 'customerAccountUrl',
customerAccountTokenExchangeUrl: 'customerAccountTokenExchangeUrl',
httpsOrigin: 'https://localhost',
exchangeForStorefrontCustomerAccessToken,
});
Expand Down Expand Up @@ -197,7 +197,7 @@ describe('auth.helpers', () => {
expiresAt: new Date().getTime() + 10000 + '',
session,
customerAccountId: 'customerAccountId',
customerAccountUrl: 'customerAccountUrl',
customerAccountTokenExchangeUrl: 'customerAccountTokenExchangeUrl',
httpsOrigin: 'https://localhost',
exchangeForStorefrontCustomerAccessToken,
});
Expand Down Expand Up @@ -228,7 +228,7 @@ describe('auth.helpers', () => {
expiresAt: '100',
session,
customerAccountId: 'customerAccountId',
customerAccountUrl: 'customerAccountUrl',
customerAccountTokenExchangeUrl: 'customerAccountTokenExchangeUrl',
httpsOrigin: 'https://localhost',
exchangeForStorefrontCustomerAccessToken,
});
Expand Down Expand Up @@ -269,7 +269,7 @@ describe('auth.helpers', () => {
expiresAt: '100',
session,
customerAccountId: 'customerAccountId',
customerAccountUrl: 'customerAccountUrl',
customerAccountTokenExchangeUrl: 'customerAccountTokenExchangeUrl',
httpsOrigin: 'https://localhost',
exchangeForStorefrontCustomerAccessToken,
});
Expand Down
18 changes: 9 additions & 9 deletions packages/hydrogen/src/customer/auth.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ export interface AccessTokenResponse {
export async function refreshToken({
session,
customerAccountId,
customerAccountUrl,
customerAccountTokenExchangeUrl,
httpsOrigin,
debugInfo,
exchangeForStorefrontCustomerAccessToken,
}: {
session: HydrogenSession;
customerAccountId: string;
customerAccountUrl: string;
customerAccountTokenExchangeUrl: string;
httpsOrigin: string;
debugInfo?: Partial<H2OEvent>;
exchangeForStorefrontCustomerAccessToken: () => Promise<void>;
Expand Down Expand Up @@ -105,7 +105,7 @@ export async function refreshToken({
};

const startTime = new Date().getTime();
const url = `${customerAccountUrl}/auth/oauth/token`;
const url = customerAccountTokenExchangeUrl;
const response = await fetch(url, {
method: 'POST',
headers,
Expand Down Expand Up @@ -139,7 +139,7 @@ export async function refreshToken({
const accessToken = await exchangeAccessToken(
access_token,
customerAccountId,
customerAccountUrl,
customerAccountTokenExchangeUrl,
httpsOrigin,
debugInfo,
);
Expand All @@ -166,7 +166,7 @@ export async function checkExpires({
expiresAt,
session,
customerAccountId,
customerAccountUrl,
customerAccountTokenExchangeUrl,
httpsOrigin,
debugInfo,
exchangeForStorefrontCustomerAccessToken,
Expand All @@ -175,7 +175,7 @@ export async function checkExpires({
expiresAt: string;
session: HydrogenSession;
customerAccountId: string;
customerAccountUrl: string;
customerAccountTokenExchangeUrl: string;
httpsOrigin: string;
debugInfo?: Partial<H2OEvent>;
exchangeForStorefrontCustomerAccessToken: () => Promise<void>;
Expand All @@ -187,7 +187,7 @@ export async function checkExpires({
locks.refresh = refreshToken({
session,
customerAccountId,
customerAccountUrl,
customerAccountTokenExchangeUrl,
httpsOrigin,
debugInfo,
exchangeForStorefrontCustomerAccessToken,
Expand Down Expand Up @@ -251,7 +251,7 @@ export function generateState() {
export async function exchangeAccessToken(
authAccessToken: string | undefined,
customerAccountId: string,
customerAccountUrl: string,
customerAccountTokenExchangeUrl: string,
httpsOrigin: string,
debugInfo?: Partial<H2OEvent>,
) {
Expand Down Expand Up @@ -282,7 +282,7 @@ export async function exchangeAccessToken(
};

const startTime = new Date().getTime();
const url = `${customerAccountUrl}/auth/oauth/token`;
const url = customerAccountTokenExchangeUrl;
const response = await fetch(url, {
method: 'POST',
headers,
Expand Down
103 changes: 103 additions & 0 deletions packages/hydrogen/src/customer/customer-account-helper.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {describe, it, expect} from 'vitest';
import {createCustomerAccountHelper, URL_TYPE} from './customer-account-helper';

const shopId = '1';
const customerAccountUrl = `https://shopify.com/${shopId}`;

describe('return correct urls', () => {
describe('when shopId is provided', () => {
const getAccountUrl = createCustomerAccountHelper(
'2024-10',
customerAccountUrl,
shopId,
);

it('returns customer account base url', () => {
expect(getAccountUrl(URL_TYPE.CA_BASE_URL)).toBe(customerAccountUrl);
});

it('returns customer account auth url', () => {
expect(getAccountUrl(URL_TYPE.CA_BASE_AUTH_URL)).toBe(
`https://shopify.com/authentication/${shopId}`,
);
});

it('returns customer account graphql url', () => {
expect(getAccountUrl(URL_TYPE.GRAPHQL)).toBe(
`${customerAccountUrl}/account/customer/api/2024-10/graphql`,
);
});

it('returns customer account authorize url', () => {
expect(getAccountUrl(URL_TYPE.AUTH)).toBe(
`https://shopify.com/authentication/${shopId}/oauth/authorize`,
);
});

it('returns customer account login scope', () => {
expect(getAccountUrl(URL_TYPE.LOGIN_SCOPE)).toBe(
'openid email customer-account-api:full',
);
});

it('returns customer account token exchange url', () => {
expect(getAccountUrl(URL_TYPE.TOKEN_EXCHANGE)).toBe(
`https://shopify.com/authentication/${shopId}/oauth/token`,
);
});

it('returns customer account logout url', () => {
expect(getAccountUrl(URL_TYPE.LOGOUT)).toBe(
`https://shopify.com/authentication/${shopId}/logout`,
);
});
});

describe('when shopId is not provided', () => {
const getAccountUrl = createCustomerAccountHelper(
'2024-10',
customerAccountUrl,
undefined,
);

it('returns customer account base url', () => {
expect(getAccountUrl(URL_TYPE.CA_BASE_URL)).toBe(customerAccountUrl);
});

it('returns customer account auth url', () => {
expect(getAccountUrl(URL_TYPE.CA_BASE_AUTH_URL)).toBe(
`${customerAccountUrl}/auth`,
);
});

it('returns customer account graphql url', () => {
expect(getAccountUrl(URL_TYPE.GRAPHQL)).toBe(
`https://shopify.com/${shopId}/account/customer/api/2024-10/graphql`,
);
});

it('returns customer account authorize url', () => {
expect(getAccountUrl(URL_TYPE.AUTH)).toBe(
`${customerAccountUrl}/auth/oauth/authorize`,
);
});

it('returns customer account login scope', () => {
expect(getAccountUrl(URL_TYPE.LOGIN_SCOPE)).toBe(
'openid email https://api.customers.com/auth/customer.graphql',
);
});

it('returns customer account token exchange url', () => {
expect(getAccountUrl(URL_TYPE.TOKEN_EXCHANGE)).toBe(
`${customerAccountUrl}/auth/oauth/token`,
);
});

it('returns customer account logout url', () => {
expect(getAccountUrl(URL_TYPE.LOGOUT)).toBe(
`${customerAccountUrl}/auth/logout`,
);
});
});
});
45 changes: 45 additions & 0 deletions packages/hydrogen/src/customer/customer-account-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export enum URL_TYPE {
CA_BASE_URL = 'CA_BASE_URL',
CA_BASE_AUTH_URL = 'CA_BASE_AUTH_URL',
GRAPHQL = 'GRAPHQL',
AUTH = 'AUTH',
LOGIN_SCOPE = 'LOGIN_SCOPE',
TOKEN_EXCHANGE = 'TOKEN_EXCHANGE',
LOGOUT = 'LOGOUT',
}

export function createCustomerAccountHelper(
customerApiVersion: string,
deprecatedCustomerAccountUrl?: string,
shopId?: string,
) {
const customerAccountUrl = shopId
? `https://shopify.com/${shopId}`
: deprecatedCustomerAccountUrl;

const customerAccountAuthUrl = shopId
? `https://shopify.com/authentication/${shopId}`
: `${deprecatedCustomerAccountUrl}/auth`;

return function getCustomerAccountUrl(urlType: URL_TYPE): string {
switch (urlType) {
case URL_TYPE.CA_BASE_URL:
// @ts-expect-error
return customerAccountUrl;
case URL_TYPE.CA_BASE_AUTH_URL:
return customerAccountAuthUrl;
case URL_TYPE.GRAPHQL:
return `${customerAccountUrl}/account/customer/api/${customerApiVersion}/graphql`;
case URL_TYPE.AUTH:
return `${customerAccountAuthUrl}/oauth/authorize`;
case URL_TYPE.LOGIN_SCOPE:
return shopId
? 'openid email customer-account-api:full'
: 'openid email https://api.customers.com/auth/customer.graphql';
case URL_TYPE.TOKEN_EXCHANGE:
return `${customerAccountAuthUrl}/oauth/token`;
case URL_TYPE.LOGOUT:
return `${customerAccountAuthUrl}/logout`;
}
};
}
Loading

0 comments on commit f336303

Please sign in to comment.