DEV Community

Rakib Ahsan
Rakib Ahsan

Posted on

Attach jwt with fetch for next js 14 server action

We're all aware of how crucial JWT is in preventing cross-site API actions. However, dealing with attaching and handling the token every time can become quite cumbersome. That's why I've taken the initiative to enhance the fetch function within Next.js 14. Let's delve into this modification and see how it streamlines our workflow!

Let's create a new file for this updated fetch function and export it as follows:

import { cookies } from "next/headers";

const baseURL = process.env.NEXT_PUBLIC_BACKEND_URL;

export async function fetchWithAuth(
  url: string,
  options: RequestInit = {}
): Promise<any> {
  try {
    const token = getTokenFromCookie();

    const headers = new Headers(options.headers);

    if (token) {
      headers.set("Authorization", `Bearer ${token}`);
    }
    const response = await fetch(baseURL + url, { ...options, headers });

    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    const data = await response.json();

    return data;
  } catch (error) {
    console.error("Error fetching data:", error);
    throw error;
  }
}

function getTokenFromCookie(): string | undefined {
  const cookieStore = cookies();
  const tokenAll = cookieStore.get("token");
  return tokenAll?.value;
}

Enter fullscreen mode Exit fullscreen mode

When it comes to setting the JWT token from the backend, assuming I'm using Laravel for the API, and setting the cookie for the login route:

import { unstable_noStore as noStore } from "next/cache";
export async function Login(data: { email: string; password: string }) {
  try {
    noStore();
    const res = await fetch(`${baseURL}/login`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        cache: "no-store",
      },
      body: JSON.stringify(data),
    });
    const responseData = await res.json();

    if (responseData.token) {
      cookies().set("token", responseData.token, {
        httpOnly: true,
        expires: new Date("2030-01-01"),
      });
    }

    return responseData;
  } catch (error) {
    console.error("Error:", error);
    throw error;
  }
}

// HttpOnly ensures security against cross-attack

Enter fullscreen mode Exit fullscreen mode

Top comments (0)