Lab - Build Customer Registration
Introduction
The final essential workflow to implement in your basic Next.js storefront is customer login. While you’ll track a customer’s authenticated state within your own application, BigCommerce will be used for the authentication itself.
In this lab, you will:
- Add a customer login page.
- Use a customer’s email and password to authenticate them with BigCommerce.
- Track a customer’s ID in a secure JWT and include it as context in all relevant GraphQL requests.
Prerequisites
This exercise builds on the basic Next.js application begun in previous labs and has the same technical requirements.
Customer account registration will not be part of this lab, so you will need a pre-existing customer in your store.
To observe the full functionality of your customer session logic, your store should contain a customer group matching the following:
- Is NOT the default customer group. (The point of this customer group is to demonstrate differences from an anonymous user.)
- Has custom pricing. (Edit the customer group and set a Storewide Discount.)
- Has restricted category access. (Edit the customer group, un-check “Customers in this group can see products in all categories across all channels” and select a limited sub-set of your headless channel’s top-level categories.)
Then make sure your store contains a customer matching the following:
- Has “Origin channel” set to your headless channel
- Has “Customer group” set to the customer group above
- Has a password set
Setup
This exercise continues where you left off previously in your basic Next.js project. Simply start the dev server from the project root if it’s not currently running:
If you need a fresh start, you can follow the instructions below to set up a new project complete with previous exercise code.
- In your terminal, run the following, replacing the path to the working directory with your own path:
- Copy
.env.exampleas.env.localand modify.env.localwith configuration details for your store. - Start the dev server process:
- Browse to the local URL printed in the
pnpmoutput and verify your catalog pages and cart load successfully.
Exercise Reference Copy
You may choose to download or clone the completed version of this lab in a separate location to serve as a reference for the final state.
Configure JWT Support
You’ll be encoding an authenticated customer’s information in a JWT to securely track their session. The library jsonwebtoken is pre-installed in the codebase and is used to manage JWTs. This library requires a secret value in order to sign JWTs.
- Run the following in your terminal to generate a random secret that will be used to sign JWTs.
- Add the secret you generated above to your
.env.localfile.
Create the Registration Page
- Open the file
app/register/page.tsx, which defines the register page component. Update the component as follows.
We’re not doing much in this page component. The reason is that basically the entire contents of the page are contained within a form, and as you’ve previously seen with the Add to Cart button, interacction requires a client component!
RegisterForm is currently empty. Let’s fill it in next.
- Open the file
components/account/register-form.tsxand modify the component as follows.
We’re using some simple state here to capture the form values, as well as tracking a “loading” state when the form is submitted.
- Fill in the
submitRegisterfunction with the request logic.
registerCustomer is another server function, which doesn’t currently accept the right parameters.
- Open the file
components/account/_actions/register-customer.tsand update the function to accept the proper parameters and return a generic error for the time being.
- Since there’s not yet a navigation link to the registration page, browse directly to
http://localhost:3000/register(or the correct port for your own local server). You can try submitting the form for a successful HTTP response, but you’ll currently receive the “Registration. is not implemented” error.
Add the Registration Logic
- Open the file
components/account/_actions/register-customer.tsand add the GraphQL and type definitions related to the registration mutation.
- Update the
registerCustomerfunction to perform the mutation.
- Browse once again to
http://localhost:3000/register(or the correct port for your own local server). - Test the register form with an email address that doesn’t match any existing customer account. A successful registration should result in being redirected to
/login(which is currently a blank page). - Verify in your store control panel that the new customer exists.
- Browse to
/registeragain and try out a registration with the same email address you used before. Verify that you receive appropriate error feedback.
Create the Login Page
The focus of the next sections will be to provide a login form, perform authentication with BigCommerce, and store a JWT in a cookie to represent the customer’s session.
- Open the file
app/login/page.tsx, which defines the login page component. Update the component as follows.
Similar to the registration page, most of what’s going on here is delegated to a client form component.
- Open the file
components/account/login-form.tsxand modify the component as follows.
- Fill in the
submitLoginfunction with the request logic.
Once again, we’re relying on a server function that must be modified to accept the right parameters.
- Open the file
components/account/_actions/login-customer.tsand modify the function as follows.
- Since there’s not yet a navigation link to the login page, browse directly to
http://localhost:3000/login(or the correct port for your own local server). You can try submitting the form for a successful HTTP response. You’ll currently see the “not implemented” message.
Add the Login Logic
- Open the file
components/account/_actions/login-customer.tsand add the GraphQL and type definitions related to the login mutation.
- Update the
loginCustomerfunction to perform the mutation.
- Browse once again to
http://localhost:3000/login(or the correct port for your own local server). - Test the login form with an incorrect email or password to observe the resulting error message.
- Test the login form with credentials for an existing customer. While there won’t yet be any visible feedback, you can use your browser dev tools to observe the
customercookie being set.
Add Header Links
Your next step will be to add contextual login/logout links in the store header, which will require awareness of a customer’s logged-in status.
- Open the file
lib/getCurrentCustomer.ts. The helper function here will be used by any component that needs to retrieve the details tracked in the “customer” cookie. Fill in the function as follows.
- Open the file
components/account-links/index.tsx. Update the component as follows.
Notice that while “Register” and “Log in” are simple links, while a separate component is included for logging out. The logout link, rather than simply linking the user to a destination, is a dynamic interaction, and so it calls for yet another client component. Let’s fill out that component’s initial content now.
- Open the file
components/account-links/logout-button.tsxand modify the component as follows.
This button doesn’t do anything yet but already has a simple loading state ready to go.
- Modify
components/header/index.tsxto placeAccountLinks.
- Browse to your local site and observe the new account link.
If you retry a valid login on the login page, you should be able to observe the links in the header immediately update accordingly.
Add Logout Logic
- Open the file
components/account-links/logout-button.tsxand modify the component to implement a submit event calling a server function.
- Open the file
components/account-links/_actions/logout.tsand add the appropriate query and response types.
- Update
logoutto perform the appropriate mutation and destroy thecustomercookie.
- Browse to your local site and make sure you’re logged in with a valid customer account. Try out the “Log Out” link in the header.
Send Customer Token in GraphQL
Your storefront will now handle authenticating and tracking a customer, but this has little actual effect except to then give the customer the chance to log out again. Let’s put the customer context to use in one of the most important ways: Passing this context in the storefront’s various GraphQL queries, which will affect the data returned.
Support for a customerToken is already built into the bcGqlFetch function, which passes this parameter in the X-Bc-Customer-Access-Token header. Each of the catalog queries you’ve built also supports a customerToken parameter. All that’s needed is to update the contexts where these queries are used to obtain and pass in the current customer’s token.
In a truly complete storefront, cart-related queries and mutations should be affected as well, but we’re not tackling the extra complexity (such as reassigning an existing guest cart to a logged-in customer) in this exercise.
- Modify
components/header/index.tsxto get the current customer using the helper function you created and pass the token into the GraphQL function.
- Modify
app/category/[...catPath]/page.tsxto perform the same customer context logic.
- Modify
app/product/[...productPath]/page.tsxto perform the same customer context logic.
- Choose a customer belonging to a group with custom pricing and without access to some top-level categories. If you don’t have such a customer, register a new customer and make the appropriate change to their customer group.
- Try out both a logged-in and logged-out state on your storefront. Make sure when logging in to use the customer account subject to price and catalog differences. You should be able to observe the differences in the contents of the main nav menu and the pricing on catalog pages.
If you try adding a product to the cart while logged in as a customer with pricing discounts, you will NOT see the same price difference in the cart. This is because the cart queries and mutations, including the initial createCart request, still lack the customer context, so cart pricing is not affected by it.
Full Lab Code
Taking It Further
Provide the token from the current customer for cart requests as well, and verify that a logged-in customer session is maintained when redirecting to checkout.