user24862332
user24862332

Reputation: 1

Next.js14 set cookie in server side axios

stack : Next.js14 App router, axios

Problem : Cookies can only be modified in a Server Action or Route Handler

Expected : set cookie with new accessToken when expired.

Hi, I'm trying to handle auth using cookies and axios.interceptors. If accessToken is expired, catch errors in axios.intercepotrs.response.use and getNewAccessToken with refreshToken. I need to set cookie with this new accessToken. But, cookies can only be set in ServerAction or Route handler. How can I set cookie to newAccessToken in server side axios.

please help. I'm dealing with this problem for 3days, and couldn't find appropriate answers. Some suggests to use page router or client-side axios, but i don't want to lose server side benefits.

instance.interceptors.response.use(
  (config) => config,
  async (error) => {
    //토큰 만료 에러
    if (error.response.status === 401) {
      const newAccessToken = await getNewAccessToken();

      if (newAccessToken) {
        error.config.headers.Authorization = `Bearer ${newAccessToken}`;
        cookies().set("accessToken", newAccessToken);
        return axios(error.config);
      } else {
        // logout
      }
    }

    return Promise.reject(error);
  },
);

I tried to redirect to call server action, but Error: NEXT_REDIRECT occured. I tried to use library cookies-next, but didn't work.

Upvotes: 0

Views: 1245

Answers (4)

Mayank Kumar Chaudhari
Mayank Kumar Chaudhari

Reputation: 18648

You can not do this simply on the server side. You also need to handled this on the client side.

A straightforward approach is this.

  1. send a 401 response to the client when the token is expired.
  2. Call the cookie API route or server function from a client that creates a new access token and sets the cookie.

Why can't we do this simply on the server side?

To understand this, you have to understand that cookies are not stored on the server but on the client side.

Upvotes: 0

mohammadreza hayati
mohammadreza hayati

Reputation: 83

I use this method for the next.js 14 and above:

'use server';

import { cookies } from 'next/headers';

const COOKIE_NAME = 'ACCESS_TOKEN';
export async function getUserAccessToken() {
    return (await cookies()).get(COOKIE_NAME)?.value;
}

export async function setUserAccessToken(accessToken: string) {
    (await cookies()).set(COOKIE_NAME, accessToken, { path: '/', maxAge: 365 * 24 * 60 * 60 });
}
 

And you can use it in axios async interceptor:

instance.interceptors.response.use(
  (config) => config,
  async (error) => {
    //토큰 만료 에러
    if (error.response.status === 401) {
      const newAccessToken = await getNewAccessToken();

      if (newAccessToken) {
        error.config.headers.Authorization = `Bearer ${newAccessToken}`;
        await setUserAccessToken(newAccessToken);
        return axios(error.config);
      } else {
        // logout
      }
    }

    return Promise.reject(error);
  },
);

Upvotes: 0

eunkyungson
eunkyungson

Reputation: 21

You should use server actions as I mentioned.

src/actions/cookie.ts

'use server'

import {
  RequestCookie,
  ResponseCookie,
} from 'next/dist/compiled/@edge-runtime/cookies'
import { cookies } from 'next/headers'

export async function setCookie(
  ...args:
    | [key: string, value: string, cookie?: Partial<ResponseCookie>]
  | [options: ResponseCookie]
) {
  cookies().set(...args)
}

your instance:

instance.interceptors.response.use(
  (config) => config,
    async (error) => {
    //토큰 만료 에러
    if (error.response.status === 401) {
      const newAccessToken = await getNewAccessToken();
      if (newAccessToken) {
        error.config.headers.Authorization = `Bearer ${newAccessToken}`;
        // cookies().set("accessToken", newAccessToken);
        await setCookie('accessToken', newAccessToken)
        return axios(error.config);
      } else {
        // logout
      }
    }

    return Promise.reject(error);
  },
);

Upvotes: 2

To handle authentication using cookies and Axios interceptors in a Next.js 14 App Router, and to set a new access token in cookies when it expires, you can follow this approach:

  1. Create an Axios Instance with Interceptors

  2. Handle Access Token Refresh in Interceptors

  3. Set Cookies in Server Actions or Route Handlers

    export const getServerSideProps: GetServerSideProps = async (
    
    context: GetServerSidePropsContext
    
    ) => {
      const { id }: any = context.query;
      const headers = context.req.headers;
    
    
      setAuthHeaders(headers);
    
      if (id) {
       const article = await requestArticleById(id);
      return {
       props: {
             article,
         },
         };
       } else {
          return { props: {} };
          }
       };
    

Upvotes: 0

Related Questions