node.js - handel custom JWT build by nodejs(api) in nextjs using authjs(v5) - Stack Overflow

I return the access token and some user data in the response while setting the refresh token in an HTTP

I return the access token and some user data in the response while setting the refresh token in an HTTP-only cookie on the server when the user logs in.

However, the refresh token is not being set in the cookie because the login request is made from a client component, while auth.js needs to work in a server component.

Problem

The refresh token does not get stored in the HTTP-only cookie.
I suspect this is because the request is coming from a client component, while the authentication logic (auth.js) needs to work in a server component.

What I'm Looking For

  • How can I properly store the refresh token in an HTTP-only cookie while using server components?
  • Is there a better approach to handle authentication in Next.js 14+** with server components?
  • Any recommended articles, books, or courses that explain secure token storage and best practices against XSS, CSRF, etc.?

My Current Approach

I'm using a signinUser function that makes a request to the /auth/login API:

// login.js
import api from "@/utils/api";

export async function signinUser({ username, password }) {
  try {
    const response = await api.post(
      `/auth/login`,
      { username, password },
      { withCredentials: true } // Ensures cookies are sent
    );

    return { data: response.data, success: "success" };
  } catch (error) {
    const errorMessage =
      error.response?.data?.message ||
      error.response?.data?.error ||
      error.response?.data?.errors?.[0]?.msg;

    return { error: errorMessage || "An error occurred. Please try again." };
  }
}

I return the access token and some user data in the response while setting the refresh token in an HTTP-only cookie on the server when the user logs in.

However, the refresh token is not being set in the cookie because the login request is made from a client component, while auth.js needs to work in a server component.

Problem

The refresh token does not get stored in the HTTP-only cookie.
I suspect this is because the request is coming from a client component, while the authentication logic (auth.js) needs to work in a server component.

What I'm Looking For

  • How can I properly store the refresh token in an HTTP-only cookie while using server components?
  • Is there a better approach to handle authentication in Next.js 14+** with server components?
  • Any recommended articles, books, or courses that explain secure token storage and best practices against XSS, CSRF, etc.?

My Current Approach

I'm using a signinUser function that makes a request to the /auth/login API:

// login.js
import api from "@/utils/api";

export async function signinUser({ username, password }) {
  try {
    const response = await api.post(
      `/auth/login`,
      { username, password },
      { withCredentials: true } // Ensures cookies are sent
    );

    return { data: response.data, success: "success" };
  } catch (error) {
    const errorMessage =
      error.response?.data?.message ||
      error.response?.data?.error ||
      error.response?.data?.errors?.[0]?.msg;

    return { error: errorMessage || "An error occurred. Please try again." };
  }
}
Share Improve this question edited Mar 20 at 23:13 Hilory 2,1417 gold badges14 silver badges30 bronze badges asked Mar 20 at 22:56 user30005873user30005873 1
Add a comment  | 

1 Answer 1

Reset to default 0

The issue is that your client component can't set HTTP-only cookies directly. Here's the simplest solution:

1. Change your:

    //  app/api/auth/login/route.js
import { NextResponse } from "next/server";

export async function POST(request) {
  try {
    const { username, password } = await request.json();
    
    // Call your actual auth API/service
    const authResponse = await fetch('https://your-auth-api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username, password }),
    });
    
    const authData = await authResponse.json();
    
    if (!authResponse.ok) {
      return NextResponse.json({ error: authData.message }, { status: 401 });
    }
    
    // Create response with access token and user data
    const response = NextResponse.json({
      user: authData.user,
      accessToken: authData.accessToken
    });
    
    // Set HTTP-only cookie with refresh token
    response.cookies.set({
      name: "refreshToken",
      value: authData.refreshToken,
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "strict",
      maxAge: 60 * 60 * 24 * 7, // 7 days
      path: "/",
    });
    
    return response;
  } catch (error) {
    return NextResponse.json({ error: "Server error" }, { status: 500 });
  }
}

2. Create a server-side route handler:

// app/api/auth/login/route.js
import { NextResponse } from "next/server";

export async function POST(request) {
  try {
    const { username, password } = await request.json();
    
    // Call your actual API/service
    const authResponse = await fetch('https://your-auth-api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username, password }),
    });
    
    const authData = await authResponse.json();
    
    if (!authResponse.ok) {
      return NextResponse.json({ error: authData.message }, { status: 401 });
    }
    
    // Create response
    const response = NextResponse.json({
      user: authData.user,
      accessToken: authData.accessToken
    });
    
    // Set HTTP-only cookie
    response.cookies.set({
      name: "refreshToken",
      value: authData.refreshToken,
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "strict",
      maxAge: 60 * 60 * 24 * 7, // 7 days
      path: "/",
    });
    
    return response;
  } catch (error) {
    return NextResponse.json({ error: "Server error" }, { status: 500 });
  }
}

The key points here:

Your client-side code stays almost the same but calls your Next.js API route The route handler makes the actual auth request to your backend The route handler sets the HTTP-only cookie using response.cookies.set() The access token is returned in the JSON response for use in memory

This approach is secure because:

Refresh token is stored in an HTTP-only cookie (protected from XSS), access token is stored in memory only (not localStorage), Next.js route handlers run on the server and can set proper HTTP-only cookies

You can implement similar route handlers for token refresh and logout operations following the same pattern. Wish you'r code the best!

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744380518a4571405.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信