I recently migrated to Nextjs from React and the architecture of Nextjs is different and confusing for me. In my next application, I am trying to authorize the API CRUD via a token that is stored in the cookie. Inside the axiosInstance, I am trying to get the token but it is outputting undefined
.
axiosInstance.ts
import axios from 'axios';
import Cookies from 'js-cookie';
const axiosInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_CLIENT_URL,
withCredentials: true,
});
axiosInstance.interceptors.request.use((config) => {
const token = Cookies.get('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default axiosInstance;
Here is the api function to get staff data.
staffAPIServices.ts
import axiosInstance from '../../axios/axiosInstance';
// Get Staff
export const getStaff = async () => {
try {
const response = await axiosInstance.get('admin/staff');
if (response.data.status) {
return response?.data?.data?.staff;
}
} catch (err: unknown) {
const errorString = err instanceof Error ? err.message : 'Unknown Error';
return err;
}
};
To showcase the staff data inside a table I have written the following code:
import clsx from 'clsx';
import { getStaff } from '@/app/utils/services/staff/staffAPIServices';
export default async function StaffTable({
query,
page,
}: {
query: string;
page: number;
}) {
interface ItemType {
id: number;
name: string;
email: string;
email_verified_at: string;
created_at: string;
updated_at: string;
deleted_at: string;
}
const staff = await getStaff();
return (
<div className="mt-6 flow-root">
<div className="inline-block min-w-full align-middle">
<div className="rounded-lg bg-gray-50 p-2 md:pt-0">
<table className="hidden min-w-full text-gray-900 md:table">
<thead className="rounded-lg text-left text-sm font-normal">
<tr>
<th scope="col" className="px-4 py-5 font-medium sm:pl-6">
ID
</th>
<th scope="col" className="px-3 py-5 font-medium">
Name
</th>
<th scope="col" className="px-3 py-5 font-medium">
Email
</th>
<th scope="col" className="px-3 py-5 font-medium">
Date
</th>
<th scope="col" className="px-2 py-5 font-medium">
Status
</th>
<th scope="col" className="relative py-3 pl-6 pr-3">
<span className="sr-only">Edit</span>
</th>
</tr>
</thead>
<tbody className="bg-white">
{Array.isArray(staff) &&
staff.map((item: ItemType) => (
<tr
key={item.id}
className="w-full border-b py-4 text-sm last-of-type:border-none [&:first-child>td:first-child]:rounded-tl-lg [&:first-child>td:last-child]:rounded-tr-lg [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg"
>
<td className="whitespace-nowrap py-3 pl-6 pr-3">
<p>{item.id}</p>
</td>
<td className="whitespace-nowrap px-3 py-4">{item.name}</td>
<td className="whitespace-nowrap px-3 py-4">
{item.email}
</td>
<td className="whitespace-nowrap px-3 py-4">
{item.created_at}
</td>
<td className="whitespace-nowrap px-3 py-4">
<span
className={clsx(
'flex items-center justify-center rounded-full px-4 py-1',
{
'bg-red-500 text-white': item.deleted_at === null,
'bg-green-500 text-white': item.deleted_at !== null,
},
)}
>
{item.deleted_at ? 'Active' : 'Inactive'}
</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
);
}
So far I have tried the following:
- Pasting the token string directly in the
Bearer fake-token-12312312
(which is working) but this violates DRY principles and I have more than 100 API functions. - Converting the
axiosInstance.ts
andstaffAPIServices.ts
into client-side components('use client'
). This didn’t work! - In another StackOverflow question someone suggested getting a cookie inside the page by converting into a client-side component but next is complaining
Prevent client components from being async functions.
2
Answers
I found the solution. By converting the
StaffTable
into a client component, the API is successfully getting the stored token cookie and the response data is getting back. However, I don't know whether this is a professional Nextjs approach.axiosInstance.ts
andstaffAPIServices.ts
are not React Components so adding'use client'
will not do anything. You need to make the components that uses these functions client-side not the functions itself.If those components are client-side and you checked that it runs in browser environment (put some
console.log
s and see if it’s printing to terminal or browser console) you can check the cookie itself:Cookies can have HttpOnly attributes set to them, in that case you can’t access them in client side. You can check that on application tab in Chrome dev tools: