Reputation: 1
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
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.
To understand this, you have to understand that cookies are not stored on the server but on the client side.
Upvotes: 0
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
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
Reputation: 1
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:
Create an Axios Instance with Interceptors
Handle Access Token Refresh in Interceptors
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