Skip to content

Commit

Permalink
move helpers toslashelper file
Browse files Browse the repository at this point in the history
  • Loading branch information
yunakim714 committed Sep 25, 2024
1 parent fc63054 commit 8322473
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 227 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
"rules": {
"@typescript-eslint/explicit-module-boundary-types": "error"
}
},
{
"files": ["./src/static/helpers/slasHelper.ts"],
"rules": {
"max-lines": "off"
}
}
],
"settings": {
Expand Down
136 changes: 0 additions & 136 deletions src/static/helpers/IDPLoginHelper.test.ts

This file was deleted.

90 changes: 0 additions & 90 deletions src/static/helpers/IDPLoginHelper.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/static/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
// Doing so may lead to circular dependencies or duplicate exports (due to rollup mangling the types)
export * from './environment';
export * from './slasHelper';
export * from './IDPLoginHelper';
export * from './types';
export * from './customApi';
export * from './fetchHelper';
55 changes: 55 additions & 0 deletions src/static/helpers/slasHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,61 @@ describe('Registered B2C user flow', () => {
});
});

describe('Social login user flow', () => {
test('loginIDPUser does not stop when authorizeCustomer returns 303', async () => {
// slasClient is copied and tries to make an actual API call
const mockSlasClient = createMockSlasClient();
const {shortCode, organizationId} = mockSlasClient.clientConfig.parameters;

// Mock authorizeCustomer
nock(`https://${shortCode}.api.commercecloud.salesforce.com`)
.get(`/shopper/auth/v1/organizations/${organizationId}/oauth2/authorize`)
.query(true)
.reply(303, {message: 'Oh yes!'});

await expect(
slasHelper.loginIDPUser(mockSlasClient, {}, parameters)
).resolves.not.toThrow(ResponseError);
});

test('generates an access token using slas private client', async () => {
const mockSlasClient = createMockSlasClient();
const {shortCode, organizationId} = mockSlasClient.clientConfig.parameters;

// Mock authorizeCustomer
nock(`https://${shortCode}.api.commercecloud.salesforce.com`)
.get(`/shopper/auth/v1/organizations/${organizationId}/oauth2/authorize`)
.query(true)
.reply(303, {response_body: 'response_body'}, {location: url});

const accessToken = await slasHelper.loginIDPUser(
mockSlasClient,
credentialsPrivate,
parameters
);

const expectedReqOptions = {
headers: {
Authorization: `Basic ${stringToBase64(
`client_id:${credentialsPrivate.clientSecret}`
)}`,
},
body: {
grant_type: 'authorization_code',
redirect_uri: 'redirect_uri',
client_id: 'client_id',
channel_id: 'site_id',
usid: '048adcfb-aa93-4978-be9e-09cb569fdcb9',
code_verifier: expect.stringMatching(/./) as string,
code: 'J2lHm0cgXmnXpwDhjhLoyLJBoUAlBfxDY-AhjqGMC-o',
dnt: 'false',
},
};
expect(getAccessTokenMock).toBeCalledWith(expectedReqOptions);
expect(accessToken).toBe(expectedTokenResponse);
});
});

describe('Refresh Token', () => {
test('refreshes the token with slas public client', () => {
const expectedBody = {
Expand Down
76 changes: 76 additions & 0 deletions src/static/helpers/slasHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,82 @@ export async function loginRegisteredUserB2C(
return slasClient.getAccessToken({body: tokenBody});
}

/**
* A single function to execute the ShopperLogin External IDP Login with proof key for code exchange flow as described in the [API documentation](https://developer.salesforce.com/docs/commerce/commerce-api/references?meta=shopper-login:Summary).
* **Note**: this func can run on client side. Only use private slas when the slas client secret is secured.
* @param slasClient a configured instance of the ShopperLogin SDK client.
* @param credentials - the clientSecret (if applicable) to login with.
* @param credentials.clientSecret? - secret associated with client ID
* @param parameters - parameters to pass in the API calls.
* @param parameters.redirectURI - Per OAuth standard, a valid app route. Must be listed in your SLAS configuration. On server, this will not be actually called. On browser, this will be called, but ignored.
* @param parameters.hint - Name of an identity provider (IDP) to redirect to
* @param parameters.usid? - Unique Shopper Identifier to enable personalization.
* @param parameters.dnt? - Optional parameter to enable Do Not Track (DNT) for the user.
* @returns TokenResponse
*/
export async function loginIDPUser(
slasClient: ShopperLogin<{
shortCode: string;
organizationId: string;
clientId: string;
siteId: string;
}>,
credentials: {
clientSecret?: string;
},
parameters: {
redirectURI: string;
hint: string;
usid?: string;
dnt?: boolean;
}
): Promise<TokenResponse> {
const codeVerifier = createCodeVerifier();

const privateClient = !!credentials.clientSecret;

const authResponse = await authorize(
slasClient,
codeVerifier,
{
redirectURI: parameters.redirectURI,
hint: parameters.hint,
...(parameters.usid && {usid: parameters.usid}),
},
privateClient
);

const tokenBody: TokenRequest = {
client_id: slasClient.clientConfig.parameters.clientId,
channel_id: slasClient.clientConfig.parameters.siteId,
code: authResponse.code,
code_verifier: codeVerifier,
grant_type: privateClient
? 'authorization_code'
: 'authorization_code_pkce',
redirect_uri: parameters.redirectURI,
usid: authResponse.usid,
...(parameters.dnt !== undefined && {dnt: parameters.dnt.toString()}),
};

// Using private client
if (credentials.clientSecret) {
const authHeaderIdSecret = `Basic ${stringToBase64(
`${slasClient.clientConfig.parameters.clientId}:${credentials.clientSecret}`
)}`;

const optionsToken = {
headers: {
Authorization: authHeaderIdSecret,
},
body: tokenBody,
};
return slasClient.getAccessToken(optionsToken);
}

return slasClient.getAccessToken({body: tokenBody});
}

/**
* Exchange a refresh token for a new access token.
* **Note**: this func can run on client side. Only use private slas when the slas client secret is secured.
Expand Down

0 comments on commit 8322473

Please sign in to comment.