Customer context in the GraphQL Storefront API

How an authenticated customer shapes GraphQL Storefront API requests

Many GraphQL Storefront API requests can carry a customer context: the identity of a signed-in shopper. Customer context is separate from the bearer token you use to authenticate the request. A storefront token, private token, or customer impersonation token authorizes your application to call the API at all; customer context tells the API which shopper the request represents.

Customer context affects requests in two distinct ways:

  • It can change the response. Many queries return data regardless of whether a customer is signed in, but return different data when one is. For example, you can query product data with no customer context, but a signed-in customer who belongs to a price list receives their customer-specific pricing in the same query. The operation works either way; the customer context only changes what comes back.
  • It can be required for the operation to work at all. Some queries and mutations do nothing, return empty data, or error without a customer context. Many of these are self-evident, such as reading the customer object or running addCustomerAddress. Others are not: the registerCompany mutation, for instance, must be called as a signed-in customer.

If an operation returns empty data or an authentication error when you expected results, confirm that you’re sending a customer context. The Operations that require customer context table lists the known cases.

How customer context is established

You establish customer context differently depending on where your code runs and what kind of authentication token you’re using.

On a Stencil storefront, customer context travels in a session cookie. The cookie is set automatically when a customer signs in through the login mutation, and the browser sends it with subsequent GraphQL requests. This is the same session cookie the storefront already tracks for the shopper, so a customer who is signed in to the storefront is automatically in context for client-side GraphQL requests. You don’t manage the cookie yourself; the browser and the storefront handle it.

The session cookie is reliable only on a Stencil storefront, where your GraphQL requests share the storefront’s domain. On a separate domain, such as a headless storefront, browser restrictions on cross-domain cookies make it unreliable. For client-side requests from another domain, or for any server-side request, use a customer access token instead.

Server-side: the customer access token

For server-to-server requests there is no browser session cookie, so you supply customer context explicitly with the X-Bc-Customer-Access-Token header. You obtain the token value with a login mutation and send it alongside your private token. The rest of this page covers how to obtain and use a customer access token.

Server-side: a customer ID header

A customer impersonation token allows you to provide customer context a third way: you send the target customer’s ID in the X-Bc-Customer-Id header, and the token authorizes the request to act as that customer without a customer login. Because a single customer impersonation token can assume the context of any customer, it is a highly sensitive credential and must stay server-side. For how to create and use one, see Customer impersonation tokens on the Authentication page.

Operations that require customer context

The following operations only return meaningful data, or only work at all, when the request carries a customer context.

This list may not be exhaustive. If you find an operation that requires customer context and isn’t listed here, let us know.

OperationNotes
Query.customerThe currently signed-in customer and its subfields (addresses, orders, attributes, stored payment instruments, wishlists).
Query.companyB2B company queries for the authenticated customer.
Mutation.customer.changePasswordChanges the signed-in customer’s password.
Mutation.customer.updateCustomerUpdates the signed-in customer’s account.
Mutation.customer.addCustomerAddressManages the signed-in customer’s address book.
Mutation.customer.updateCustomerAddressManages the signed-in customer’s address book.
Mutation.customer.deleteCustomerAddressManages the signed-in customer’s address book.
Mutation.customer.updateStoredPaymentInstrumentManages the signed-in customer’s stored payment instruments.
Mutation.customer.deleteStoredPaymentInstrumentManages the signed-in customer’s stored payment instruments.
Mutation.company.registerCompanyMust run as a signed-in customer.
Mutation.company.updateCompanyUserUpdates the authenticated company user’s account.
Mutation.wishlist.*createWishlist, addWishlistItems, updateWishlist, deleteWishlistItems, and deleteWishlists all act on the signed-in customer’s wishlists.

By contrast, operations that create or recover an account do not require an existing customer context, because you use them precisely when no customer is signed in yet: registerCustomer, login, loginWithCustomerLoginJwt, requestResetPassword, and resetPassword.

Customer access tokens

A customer access token is unique to an individual user’s account because it represents an authenticated storefront session for GraphQL requests. You can obtain and use a customer access token only for server-to-server requests. Therefore, you must use the customer access token alongside a private token. A customer access token becomes invalid on all devices when you log out of a single device.

Do not use this token for client-side requests.

Obtaining a customer access token

There are two options to obtain a customer access token.

  1. Login mutation
  2. Login with a JWT

Login mutation

Enter your user email and password to use the login mutation. When using the login mutation in a server-to-server context, the mutation will return a customer access token in response to login actions as part of the GraphQL body instead of a cookie header. From there, you can store the customer access token in the presentation layer’s session management system and send it with future GraphQL requests. If the login mutation request is from a browser, we will not return the customer access token in the body, and will instead set a cookie.

  • Use the Create a Token endpoint to generate a storefront bearer token, or the Create a Private Token endpoint to generate a private token, needed to run the login mutation call.

  • If you request a customer access token in wrong communication context, you will receive the following error: Customer access token was requested in the body, but it’s only returned for server-to-server requests. For browser requests it’s set as an httpOnly cookie instead.

  • If you still have issues creating a customer access token, we recommend clearing your cookies to resolve any loading issues.

Example login mutation: Create a customer access token
# Creates a customer access token
POST https://{{storeDomain}}/graphql
Authorization: Bearer {Private token}
accept: application/json
content-type: application/json
mutation Login($email: String!, $pass: String!) {
login(email: $email, password: $pass) {
result
customer {
entityId
email
}
customerAccessToken {
value
expiresAt
}
}
}
GraphQL variables
{
"email": "user@email.com",
"pass": "password"
}

Login with a JWT

There are two options for logging in using a JWT.

  1. Customer Login API

The Customer Login API enables third-party services to securely authenticate a logged-in customer by accepting a signed JWT from BigCommerce. This allows the third party to verify the customer’s identity before granting access to sensitive information. For more details, see the Customer Login API article.

  1. loginWithCustomerLoginJwt

The loginWithCustomerLoginJwt mutation allows you to pass a customer JSON web token instead of the user’s email and password. A 3rd party signs the JSON web token used. In this scenario, you will generate a JWT that contains key information in the payload for the login to be successful. You will use this JWT in the login mutation to receive a customer access token. For instructions on creating a JWT, see the Customer Login API article for instructions.

Example JWT login mutation: Create a customer access token
# Creates a customer access token
POST https://{{storeDomain}}/graphql
Authorization: Bearer {Private token}
accept: application/json
content-type: application/json
mutation Login($jwt: String!) {
loginWithCustomerLoginJwt(jwt: $jwt) {
customer {
entityId
email
}
customerAccessToken {
value
expiresAt
}
}
}
GraphQL variables
{"jwt": "your_jwt_token"}

Using a customer access token

You can assign the customer access token obtained using one of the mutations described above to the X-Bc-Customer-Access-Token header for future queries. You can use this token for a specific shopper session access until it is invalidated or if it expires due to time. The token is invalidated when you use the logout mutation with the X-Bc-Customer-Access-Token header.

Example customer query
POST https://{{storeDomain}}/graphql
Authorization: Bearer {Private token}
X-Bc-Customer-Access-Token: {Customer access token}
accept: application/json
content-type: application/json
query CustomerAttributes {
customer {
firstName
lastName
email
entityId
customerGroupId
attributeCount
attributes {
shirtSize: attribute(entityId:123) {
entityId
value
}
favoriteColor: attribute(entityId:456) {
entityId
value
}
}
}
}

Further reading