admin管理员组文章数量:1129677
My React Next.JS Application calls a REST API External and receives tokens in Cookies for authentication (Access and Refresh Tokens), like this picture below:
.png
I use Server Actions to fetch this REST API, maintaining sensitive information such as login and password on the server side.
In my Server Action I set those cookies in my client and send those cookies to each request the REST API in the request header, like this:
const proxyServerCookies = (cookieNames, response) => {
if (response.headers.has('set-cookie')) {
const cookieString = response.headers.get('set-cookie');
const cookieObject = setCookieParser.parse(setCookieParser.splitCookiesString(cookieString), {
map: true,
});
cookieNames.forEach(async (cookieName) => {
if (cookieObject[cookieName]) {
const cookie = cookieObject[cookieName];
await cookies().set(cookieName, cookie.value, {
//The problem is right here. If i put the line below the cookie in path /auth, like I received from the REST API, it does not show in the browser client.
//path: cookie.path,
path: '/',
maxAge: cookie.maxAge,
sameSite: (cookie.sameSite),
expires: cookie.expires,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
});
}
});
}
}
The problem is that the refreshToken cookie that I receive from the REST API comes with the path /auth and keeping this path the Action Server cannot write to the client, or at least I don't see it in the browser's cookie list.
When I change the path to root / the cookie recording works.
Could anyone tell me why this behavior?
My React Next.JS Application calls a REST API External and receives tokens in Cookies for authentication (Access and Refresh Tokens), like this picture below:
https://i.sstatic.net/TMa5rcuJ.png
I use Server Actions to fetch this REST API, maintaining sensitive information such as login and password on the server side.
In my Server Action I set those cookies in my client and send those cookies to each request the REST API in the request header, like this:
const proxyServerCookies = (cookieNames, response) => {
if (response.headers.has('set-cookie')) {
const cookieString = response.headers.get('set-cookie');
const cookieObject = setCookieParser.parse(setCookieParser.splitCookiesString(cookieString), {
map: true,
});
cookieNames.forEach(async (cookieName) => {
if (cookieObject[cookieName]) {
const cookie = cookieObject[cookieName];
await cookies().set(cookieName, cookie.value, {
//The problem is right here. If i put the line below the cookie in path /auth, like I received from the REST API, it does not show in the browser client.
//path: cookie.path,
path: '/',
maxAge: cookie.maxAge,
sameSite: (cookie.sameSite),
expires: cookie.expires,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
});
}
});
}
}
The problem is that the refreshToken cookie that I receive from the REST API comes with the path /auth and keeping this path the Action Server cannot write to the client, or at least I don't see it in the browser's cookie list.
When I change the path to root / the cookie recording works.
Could anyone tell me why this behavior?
Share Improve this question asked Jan 8 at 8:49 JoaoJoao 115 bronze badges New contributor Joao is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 10 | Show 5 more comments1 Answer
Reset to default 0I was a little confused with how cookies work, but my friend @mr mcwolf helped me review the concepts and the solution to the problem follows:
I make requests to an external REST API that returns two access cookies in the response, an AccessToken in the '/' path and the RefreshToken in the '/auth' path (The address to use the Refresh Token is https://api_domain/auth/refresh-token).
In my NextJS client, I basically use interceptors to check when the AccessToken has expired and use RefreshToken to update it.
However, in the first attempt I do not have AccessToken or RefreshToken, making it necessary to use the Login/Password credentials to log into the REST API, which is why I used NextJS's Actions Servers, to leave this sensitive data only on the server side.
Therefore, I had to manually write and read cookies through the Action Server as requests would be made from them. I simply took the cookies coming from the REST API (AccessToken and RefreshToken) and created a copy of the client's browser, via the Action Server. According to the post code.
When the client tried to access an address on my website (https://my_domain/app/access), the Server Action was asked to take care of it, sending the request to the REST API. The access token has expired and the Action Server must use the RefreskToken to refresh in the REST API at https://api_domain/auth/refresh-token. This is where I got confused, the Action Server was unable to read the contents of this RefreshToken cookie as it was sent via the /app subdomain, therefore it did not reach the Action Server at that time and was not able to relay it to the REST API at https:// /api_domain/auth/refresh-token.
As the only sensitive data in this scenario are the Login/Password credentials for the first access to obtain the tokens, I placed only this in an Action Server to be handled on the server side, and kept the interceptors as client components, therefore REST API records cookies directly on the client and the RefreshToken in '/auth' will be sent correctly to https:// /api_domain/auth/refresh-token.
//apiLogin.js
'use server';
import axios from 'axios';
import setCookieParser from 'set-cookie-parser';
import { cookies } from 'next/headers';
const proxyServerCookies = (cookieNames, response) => {
if (response.headers.has('set-cookie')) {
const cookieString = response.headers.get('set-cookie');
const cookieObject = setCookieParser.parse(setCookieParser.splitCookiesString(cookieString), {
map: true,
});
cookieNames.forEach(async (cookieName) => {
if (cookieObject[cookieName]) {
const cookie = cookieObject[cookieName];
await cookies().set(cookieName, cookie.value, {
path: cookie.path,
domain: cookie.domain,
maxAge: cookie.maxAge,
sameSite: (cookie.sameSite),
expires: cookie.expires,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
});
}
});
};
};
export const apiLogin = async () => {
const response = await axios.post(process.env.NEXT_PUBLIC_API_APP + '/auth/login',
{
name: process.env.API_USERNAME,
password: process.env.API_PASSWORD
});
proxyServerCookies(['accessToken', 'refreshToken'], response);
}
//axiosPrivate.js
'use client';
import axios from 'axios';
import { apiLogin } from './apiLogin';
const axiosPrivate = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_APP,
withCredentials: true
});
axiosPrivate.interceptors.request.use(
async (config) => {
config.timeout = 5000;
return config;
}, (error) => Promise.reject(error)
);
axiosPrivate.interceptors.response.use(
response => response,
async (error) => {
const prevRequest = error?.config;
if (error.response?.status === 401 &&
(error.response.data?.code === 'AccessTokenExpired' || error.response.data?.code === 'AccessTokenNotFound')
) {
try {
await axios.post(process.env.NEXT_PUBLIC_API_APP + '/auth/refresh-token', {},
{ withCredentials: true }
);
return axiosPrivate(prevRequest);
} catch (error) {
try {
//Here is the call to Action Server with sensitive data that will be processed on the server side.
await apiLogin();
return axiosPrivate(prevRequest);
} catch (error) {
return Promise.reject(error);
};
};
};
return Promise.reject(error);
}
);
export default axiosPrivate;
本文标签: nextjs13SetCookie in Server Action doesn39t work with path authStack Overflow
版权声明:本文标题:next.js13 - Set-Cookie in Server Action doesn't work with path auth - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736747268a1950847.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Set-Cookie: accessToken=value; path=/; ...
andSet-Cookie: refreshToken=value; path=/auth; ...
. Show them so we can see if the server is sending them at all and what parameters they have (the values are not needed, you can hide them with fake ones). – mr mcwolf Commented Jan 9 at 6:17