Store Hugs Developers

Shopper sign-in

Shoppers sign in on the shop's own page, with OAuth (authorization code with S256 PKCE). Your site gets their tokens and never sees their password.

  1. In the panel, add your site's return address to a publishable key's Sign-in return addresses. The key's client id is shown below it.
  2. Make a PKCE pair and a state, keep them, and send the shopper to authorizeUrl.
  3. On your return address, check the state and trade the code with exchangeCode.
  4. Act as the shopper with withAccessToken, and renew the tokens with refresh.

Access tokens last an hour and refresh tokens 30 days.

Reach these through storefront.signIn. The PKCE pair and state come from the PKCE helpers.

Build the sign-in address

storefront.signIn.authorizeUrl(params: {
    clientId: string;
    redirectUri: string;
    state: string;
    codeChallenge: string;
}): string

The shop's sign-in page to send the shopper to: https://{host}/account/authorize with these query values:

Query value Value
client_id The client id you pass.
redirect_uri The return address you pass.
response_type code
scope storefront:customer
state The state you pass.
code_challenge The PKCE challenge you pass.
code_challenge_method S256

Parameters

Parameter Type
params.clientId string The publishable key's client id.
params.redirectUri string One of the key's sign-in return addresses.
params.state string A random value you keep, to check on the return address.
params.codeChallenge string The challenge of the PKCE pair whose verifier you keep.

Returns

The address, as a string. No request is made.

Example

import { createPkcePair, createState } from '@storehugs/integration';

const { verifier, challenge } = await createPkcePair();
const state = createState();
sessionStorage.setItem(
    'storehugs_sign_in',
    JSON.stringify({ verifier, state }),
);

window.location.assign(
    storefront.signIn.authorizeUrl({
        clientId: 'the-key-client-id',
        redirectUri: 'https://www.example.com/account/callback',
        state,
        codeChallenge: challenge,
    }),
);

Exchange the code

storefront.signIn.exchangeCode(params: {
    code: string;
    clientId: string;
    redirectUri: string;
    codeVerifier: string;
}): Promise<TokenSet>

Trades the code from the redirect for the shopper's tokens, with the authorization_code grant. No Idempotency-Key is sent.

Parameters

Parameter Type
params.code string The code query value on your return address.
params.clientId string The publishable key's client id.
params.redirectUri string The same return address you sent the shopper with.
params.codeVerifier string The verifier of the PKCE pair you kept.

Returns

A TokenSet:

FieldTypeDescription
token_typestringOne of Bearer.
expires_inintegerSeconds (3600).
access_tokenstring
refresh_tokenstring

Errors

StatusWhen
400An OAuth error (invalid_request, invalid_grant, unsupported_grant_type…).
401invalid_client: not the client id of one of this shop's active publishable keys.
402The shop is suspended (message only).
403The shop is not live.
404Not found, or the shop's plan has no Integration API.
429Rate limited.

Example

const params = new URLSearchParams(window.location.search);
const saved = JSON.parse(sessionStorage.getItem('storehugs_sign_in')!);

if (params.get('state') !== saved.state) {
    throw new Error('Sign-in state does not match');
}

const tokens = await storefront.signIn.exchangeCode({
    code: params.get('code')!,
    clientId: 'the-key-client-id',
    redirectUri: 'https://www.example.com/account/callback',
    codeVerifier: saved.verifier,
});

Refresh the tokens

storefront.signIn.refresh(params: { refreshToken: string; clientId: string }): Promise<TokenSet>

New tokens for a refresh token, with the refresh_token grant, before or after the access token runs out.

Parameters

Parameter Type
params.refreshToken string The shopper's refresh token.
params.clientId string The publishable key's client id.

Returns

A TokenSet:

FieldTypeDescription
token_typestringOne of Bearer.
expires_inintegerSeconds (3600).
access_tokenstring
refresh_tokenstring

Errors

StatusWhen
400An OAuth error (invalid_request, invalid_grant, unsupported_grant_type…).
401invalid_client: not the client id of one of this shop's active publishable keys.
402The shop is suspended (message only).
403The shop is not live.
404Not found, or the shop's plan has no Integration API.
429Rate limited.

Example

const fresh = await storefront.signIn.refresh({
    refreshToken: tokens.refresh_token,
    clientId: 'the-key-client-id',
});

Act as the shopper

storefront.withAccessToken(accessToken: string): StorefrontClient

The same client, acting for a signed-in shopper: it sends the access token with every request, next to the key. The original client is unchanged.

Parameters

Parameter Type
accessToken string The shopper's access token.

Returns

A new StorefrontClient. No request is made.

Example

const shopper = storefront.withAccessToken(tokens.access_token);
const me = await shopper.customer.get();