In the backend, I send the access token and refresh token in the response by jwt, and in the nextjs 14 app router, I save them in the cookie after the user login.
Now, the problem I have is when the user’s access token expires, I generate a new token for him by refreshing the token, but I encounter the same error.
this is my refreshAccessToken function for get a new access toke:
'use server'
import {cookies} from "next/headers";
import {isTokenExpiringSoon} from "@/app/utils/utils";
import {modifiedCookie} from "@/app/_actions/modifiedCookie";
export async function refreshAccessToken(refreshToken) {
console.log("Attempting to refresh access token...");
if (!refreshToken) {
console.error('Refresh token not found');
throw new Error('Refresh token not found');
}
const refreshResponse = await fetch(`http://localhost:8000/api/token/refresh/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
refresh: refreshToken,
}),
});
if (!refreshResponse.ok) {
console.error('Failed to refresh token:', refreshResponse.statusText);
throw new Error('Failed to refresh token');
}
console.log('working on it')
const data = await refreshResponse.json();
const newAccessToken = data.access;
console.log(`newAccessToken in refresh: ${newAccessToken}`)
modifiedCookie(newAccessToken)
console.log("New access token set:", newAccessToken);
return newAccessToken;
}
and this is my fetchUserData function for get user data:
export async function fetchUserData() {
const cookieStore = cookies();
const accessToken = cookieStore.get('access_token')?.value;
console.log("Current access token in fetch:", accessToken);
if (isTokenExpiringSoon(accessToken)) {
console.log("Access token is expiring soon, refreshing...");
try {
const refreshToken = cookieStore.get('refresh_token')?.value;
console.log("Refresh Token:", refreshToken);
await refreshAccessToken(refreshToken);
} catch (error) {
console.error('Error refreshing access token:', error);
throw new Error('Unable to refresh access token');
}
}
const newAccessToken = cookieStore.get('access_token')?.value;
console.log("New access token to use:", newAccessToken);
const response = await fetch(`http://localhost:8000/api/user/user-profile/`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${newAccessToken}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) {
console.error('Failed to fetch user profile:', response.statusText);
throw new Error('Failed to fetch user profile');
}
const user = await response.json();
console.log("Fetched user data:", user);
return user;
}
After this i get this error:
Current access token in fetch: ey…
Access token is expiring soon, refreshing…
Refresh Token: ey…
Attempting to refresh access token…
working on it
newAccessToken in refresh: ey…
New access token set: ey…
New access token to use: ey…
tA [Error]: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options
at Proxy.callable (/home/comiser/Desktop/tasteproject/frontend/tastecoffee/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:36:13455)
at modifiedCookie (webpack-internal:///(rsc)/./app/_actions/modifiedCookie.js:14:61)
at refreshAccessToken (webpack-internal:///(rsc)/./app/_actions/actions.js:41:80)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async fetchUserData (webpack-internal:///(rsc)/./app/_actions/actions.js:54:13)
at async RootLayout (webpack-internal:///(rsc)/./app/layout.js:38:16)
Failed to fetch user profile: Unauthorized
Error fetching user profile: Failed to fetch user profile