Using the Customer Account API with Hydrogen
This tutorial creates a login button on a Hydrogen storefront that lets a customer authenticate using the Customer Account API and if successful, displays a welcome message with their email address.
What you'll learn
Anchor link to section titled "What you'll learn"After you've completed this tutorial, you'll be able to authenticate a Customer and make Customer Account API queries within a Hydrogen storefront.
Requirements
Anchor link to section titled "Requirements"- You have completed the Getting started with the Customer Account API guide.
- You have completed Getting started with Hydrogen guide.
- You've installed the Headless or Hydrogen sales channel from the Shopify App Store.
Step 1: Create login button
Anchor link to section titled "Step 1: Create login button"The first step is to create a simple login button in the your storefront. This button will route to the /authorize
endpoint which we will create in the next section.
Step 2: Create authorize route
Anchor link to section titled "Step 2: Create authorize route"Visit the Hydrogen Customer Account API settings and note the Client ID under Customer Account API credentials. Shopify stores the client ID in the .env
file under PUBLIC_CUSTOMER_ACCOUNT_CLIENT_ID
.
Also note the Authorization endpoint under Application Endpoints in the settings and use it as the loginUrl
to redirect the user to log them in.
While you're in the settings, add http://localhost:3000/authorize
or if using Oxygen, the auto-generated host as a Callback URI(s) under Application setup.
In your storefront, create an authorize.tsx
route under /routes/
and fill out the action
function:
Step 3: Generate code challenge and verifier
Anchor link to section titled "Step 3: Generate code challenge and verifier"The previous step redirects the customer to the login page, but it isn't sufficient to authorize them. We need to add a Code Challenge and Verifier to the loginUrl
params.
Let's add the following code to authorize.tsx
. It will generate the verifier and code challenge then set them as parameters of the login request. We also store the verifier in the session for use in future steps.
Step 4: Add state and nonce
Anchor link to section titled "Step 4: Add state and nonce"In order to mitigate CSRF attacks, the use of the state
parameter is required. Optionally, you can also pass a nonce
parameter in order to mitigate replay attacks. Both are random values that you must generate and persist in your application.
Let's add the following code to authorize.tsx
to add our state and nonce
to the session and as parameters for the loginUrl
.
Step 5: Decode nonce
Anchor link to section titled "Step 5: Decode nonce"Before we move on, let's add some code to authorize.tsx
that will aid us in retrieving the nonce
so we can compare it against the one we generated in the previous step.
Step 6: Fetch access token
Anchor link to section titled "Step 6: Fetch access token"The customer will be redirected to redirect_uri
upon completing authentication (in our case this is /authorize
). Let's add code to the loader
function to retrieve the code
and state
parameters then fetch the access_token
.
Back in the Hydrogen storefront's Customer Account API settings, we will note the Token endpoint under Application Endpoints and use it as the tokenRequestUrl
to request the access token.
We will verify that code
and state
are returned and then we will request a token. A successful request will return the following values:
Query parameter | Description |
---|---|
access_token |
A credential that authorizes a client application to access protected resources on behalf of a user. It will be used as part of token exchange to retrieve another access_token for the Customer Account API. |
expires_in |
The number of seconds until the access token expires. |
refresh_token |
a credential that allows a client application to obtain a new access token without requiring the user to reauthenticate. It will be used to retrieve a new access_token when the current access_token approaches it's expires_in time. |
id_token |
JSON Web Token (JWT) that contains user identity information. Primarily used for logging out and verifying the nonce . |
We will store these values in the session and verify the nonce
.
Response codes
Anchor link to section titled "Response codes"You might encounter the following response codes:
Response code | Message | Solution |
---|---|---|
400 |
invalid_grant |
Remove padding (for example, = ) from base64-encoded code challenge. Replace "+" with "-" and "/" with "_" to ensure compatibility with URL encoding. |
401 |
invalid_client |
Verify that the client_ID is correct. |
401 |
invalid_token (in www-authenticate header) |
Specify an origin header in the request. Add it to the list of JavaScript Origin(s) in the Customer Account API settings page. |
403 |
You don't have permission to access this website |
Specify a user-agent header in the request. |
Step 7: Token exchange for Customer Account API
Anchor link to section titled "Step 7: Token exchange for Customer Account API"You can implement Token Exchange with the Customer Account API. This involves exchanging your previously received access_token
with that of the target application (the Customer Account API). You can add a new function to authorize.tsx
to exchange your storefront's access_token
in return for the Customer Account API's access_token
.
Step 8: Query the Customer Account API
Anchor link to section titled "Step 8: Query the Customer Account API"Now that we have the Customer Account API access_token
, we can start querying the API. In this example, we will display the customer's email address on the storefront if they login succesfully.
Let's move back to _index.tsx
that we created earlier and add a loader
function that checks for the existence of the Customer Account API access_token
.
If it doesn't exist we return null, representing that a customer is not logged in; if it does exist then we can go ahead and query the API.
We first want to change .env
to include CUSTOMER_API_VERSION
with a value of unstable
. We can then make a POST request to the Customer Account API endpoint that includes an Authorization
header with the Customer Account API access_token
(stored as customer_access_token
in the session).
We will also change our template to accomodate the existance of a logged in customer.
Step 9: Log out
Anchor link to section titled "Step 9: Log out"Now that we can call the Customer Account API, let's close the loop by adding logout functionality.
Let's change the _index.tsx
template to add a welcome message when a user is logged in and a button to logout that points to a new logout.tsx
route.
Now go back to the Hydrogen or Headless admin Customer Account API settings and note the Logout endpoint.
In logout.tsx
we define a action
function that clears out our private session and retrieves the id_token
. We then redirect the user to the Logout endpoint with an id_token_hint
parameter containing the id_token
we retrieved earlier.
When a user clicks logout, it will redirect the user to the Logout URI
defined in the Customer Account API settings. If no value is provided, it will redirect to shopify.com
Step 10: Refresh access token
Anchor link to section titled "Step 10: Refresh access token"An access_token
has a time of expiry defined by the expires_in
value that was returned in an earlier step. You can add some code to check if the access_token
is close to expiry and, if so, refresh it so the user doesn't experience any disruptions.
Let's change authorize.tsx
to calcuate an expires_at
to keep track of when the access_token
will expire.
Next we move to _index.tsx
to add a refreshToken
function that will work similarly to Step 6: Fetch Access Token. In this case, the grant_type
will be refresh_token
and we add a refresh_token
parameter with the value received in the step above.
This will return a new set of access_token
, expires_in
and refresh_token
to use next time.
Finally we add a isLoggedIn
function that will help us keep track of if a user is logged in and help us refresh the access_token
if we are getting close to the expiry time.
- Explore the GraphQL Customer Account API reference.
- Explore the full Customer Account API Example
- Learn how to Manage customer accounts with the Customer Account API