Part 58: Implementing Authentication and Shopping Cart Functionality in Next.js with Strapi
[Pages] Authentication

In today's post, we are going to enhance our product page by adding the ability for users to purchase products. To achieve this, we'll integrate a shopping cart feature and implement user authentication using Strapi as our backend. We'll walk through the process of handling authentication requests, managing JSON Web Tokens, and setting up user registration.
Step 1: Understanding Authentication with Strapi
Strapi provides a robust authentication mechanism through its API. The key steps for authenticating a user are logging in, obtaining a token, and using this token for subsequent requests. Let's explore how these steps are implemented.
Logging In
When a user attempts to log in, we need to send a POST request to the /auth/local endpoint with their credentials.
# REST Client example for login request
POST /auth/local HTTP/1.1
Content-Type: application/json
{
"identifier": "[email protected]",
"password": "Alice123"
}Identifier: This can be either the username or the email. We use email for our implementation.
Password: The user's password.
Upon successful login, Strapi returns a JSON Web Token (JWT), which is essential for authenticating further requests.
Handling the JWT
The JWT received after a successful login must be stored securely in our application. For any request that requires authentication, such as accessing cart items, we include this token in the Authorization header.
# REST Client example for authenticated request
GET /cart-items HTTP/1.1
Authorization: Bearer <your-jwt-token>This token acts as proof of authentication and needs to be appended to any request requiring user verification.
Step 2: Registering a New User
Besides logging in existing users, our application should allow new users to register. The registration process is similar to logging in, but it involves a POST request to /auth/local/register.
# REST Client example for registration request
POST /auth/local/register HTTP/1.1
Content-Type: application/json
{
"email": "[email protected]",
"username": "Charlie",
"password": "Charlie123"
}Email: The new user's email.
Username: A unique username for the new user.
Password: A secure password for the user.
Upon successful registration, Strapi returns the user details and a JWT, similar to the login response.
Step 3: Implementing the Shopping Cart
With authentication in place, we can now focus on adding the shopping cart functionality. This involves creating an "Add to Cart" button on the product page, which allows authenticated users to add items to their cart.
Adding the "Add to Cart" Button
Let's add a button to our ProductPage component. When clicked, this button will trigger an API request to add the product to the user's cart.
// pages/products/[id].js
import { useState } from 'react';
import Head from 'next/head';
import Image from 'next/image';
import Title from '../../components/Title';
import { ApiError } from '../../lib/api';
import { getProduct, getProducts } from '../../lib/products';
function ProductPage({ product }) {
const [message, setMessage] = useState('');
const handleAddToCart = async () => {
try {
const response = await fetch('/cart-items', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${localStorage.getItem('jwt')}`,
},
body: JSON.stringify({ productId: product.id }),
});
if (response.ok) {
setMessage('Product added to cart!');
} else {
setMessage('Failed to add product to cart.');
}
} catch (error) {
console.error('An error occurred:', error);
setMessage('An error occurred. Please try again.');
}
};
return (
<>
<Head>
<title>{product.title}</title>
</Head>
<main className="px-6 py-4">
<Title>{product.title}</Title>
<div className="flex flex-col lg:flex-row">
<div>
<Image src={product.pictureUrl} alt="" width={640} height={480} priority />
</div>
<div className="flex-1 lg:ml-4">
<p className="text-sm">
{product.description}
</p>
<p className="text-lg font-bold mt-2">
{product.price}
</p>
<button onClick={handleAddToCart} className="mt-4 bg-blue-500 text-white py-2 px-4 rounded">
Add to Cart
</button>
{message && <p>{message}</p>}
</div>
</div>
</main>
</>
);
}
export async function getStaticPaths() {
const products = await getProducts();
const paths = products.map(product => ({
params: { id: product.id.toString() },
}));
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
try {
const product = await getProduct(params.id);
return { props: { product } };
} catch (err) {
if (err instanceof ApiError && err.status === 404) {
return { notFound: true };
}
throw err;
}
}
export default ProductPage;Explanation:
Button Click Handler: The
handleAddToCartfunction sends a POST request to add the product to the user's cart. It includes the JWT in theAuthorizationheader.Feedback Messages: The user receives feedback on whether the product was successfully added to the cart.
Conclusion
By integrating authentication and shopping cart functionality, we've significantly improved our e-commerce application. Users can now log in, register, and add products to their cart, with all interactions securely authenticated. In future posts, we'll explore additional features such as user profiles and order management, enhancing the shopping experience even further.
Last updated