Как установить файлы cookie с серверной части на производство? (выразить + отреагировать)Javascript

Форум по Javascript
Ответить
Anonymous
 Как установить файлы cookie с серверной части на производство? (выразить + отреагировать)

Сообщение Anonymous »

Я пытаюсь установить файлы cookie из серверной части, но интерфейс (браузер) продолжает их автоматически удалять. Это происходит только в рабочей среде, а не на локальном хосте.
Поток файлов cookie следующий:

Код: Выделить всё

user clicks login with discord
redirected to discord's oauth page
discord sends the data to my backend api
user account is created/updated on my database
redirects back to my authCallback page
sends another request to users/sessions to store the user's data in cookies
/sessions route sets the cookies
и серверная часть, и внешний интерфейс размещены на Vercel (monorepo)
единственный маршрут, который вызывает функцию cookie, — это пользователи/сессии
Вот необходимый код:
у меня есть 2 vercel.json, 1 для внешнего интерфейса и один для внутреннего интерфейса (на случай, если кому-то понадобится знать)
vercel.json (интерфейс):

Код: Выделить всё

{
"rewrites":
[
{
"source": "/(.*)",
"destination": "/"
}
]
}
vercel.json (серверная часть)

Код: Выделить всё

{
"builds": [
{
"src": "/index.js",
"use": "@vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/index.js",
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
}
]
}
index.js (бэкэнд — материал Cors)

Код: Выделить всё

const allowedOrigins = [
// Front End
"http://localhost:5173",
prodDomain,

// Back End
"http://localhost:4000",
prodDomainAPI,
];

app.set("trust proxy", 1);

app.use(
cors({
credentials: true,
origin: (origin, callback) => {
if (allowedOrigins.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
})
);

app.use(cookieParser());
app.use(json());
app.use(urlencoded({ extended: true }));
cookieUtils.js (бэкэнд)

Код: Выделить всё

export const setAuthCookies = (res, userData, token) => {
const commonOptions = {
path: "/",
sameSite: "None",
secure: true,
maxAge: 30 * 24 * 60 * 60 * 1000,
};

res.cookie("authUser", JSON.stringify(userData), {
...commonOptions,
httpOnly: false,
});

res.cookie("authToken", token, {
...commonOptions,
httpOnly: true,
});

return res;
};

export const clearAuthCookies = (res) => {
const clearOptions = {
path: "/",
sameSite: "None",
secure: true,
httpOnly: true,
};

res.clearCookie("authToken", clearOptions);
return res;
};
usersControllers.js (только серверная часть — маршрут /sessions)

Код: Выделить всё

users.post("/sessions", requireAuth(), async (req, res) => {
const decodedUserData = req.user.decodedUser;

try {
const existingUser = await getUserByID(decodedUserData.id);
if (!existingUser) {
return res.status(404).send("User not found");
}

const userRole = await getUserRole(decodedUserData.id);

const userData = {
id: existingUser.id,
discord_id: existingUser.discord_id,
username: existingUser.username,
avatar_url: existingUser.avatar_url,
banner_color: existingUser.banner_color,
banner_url: existingUser.banner_url,
role: userRole,
created_at: existingUser.created_at,
};

setAuthCookies(res, userData, req.user.token);

res.status(200).json({
success: true,
message: "Session established successfully",
});
} catch (error) {
console.error("users.POST /sessions", { error });
res.status(500).send("Internal Server Error");
}
});
Примечание: requireAuth работает только с JWT. Он не занимается настройкой файлов cookie, поэтому включать его нет необходимости.
AuthCallback.jsx (интерфейс)

Код: Выделить всё

export const AuthCallback = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();

useEffect(() => {
const run = async () => {
const reason = searchParams.get("reason");
const token = searchParams.get("token");

if (reason) {
let errorMessage = null;

switch (reason) {
case "rate_limited":
errorMessage =
"Discord is rate limiting login attempts. Please wait a few minutes and try again.";
break;
case "auth_failed":
errorMessage = "Authentication failed. Please try again.";
break;
default:
errorMessage = "An error occurred during authentication.";
}

toast.error(errorMessage, {
containerId: "notify-failure",
});
return setTimeout(() => {
navigate("/");
}, 1000);
}

try {
// No token means backend error
if (!token) {
toast.error("Authentication failed. Please try again.", {
containerId: "notify-failure",
});
return setTimeout(() => {
navigate("/");
}, 1000);
}

await axios
.post(
`${API}/users/sessions`,
{},
{
headers: {
Authorization: `Bearer ${token}`,
},
withCredentials: true,
},
)
.then((res) => {
toast.success("Successfully logged in!", {
containerId: "notify-success",
});
})
.catch((err) => {
toast.error("Failed to load user data. Please try again.", {
containerId: "notify-failure",
});
});

} catch (err) {
console.error("OAuth callback error:", err);
toast.error("Failed to load user data. Please try again.", {
containerId: "notify-failure",
});
} finally {
// Only reload if we have a token (success case)
if (token) {
console.log("token received");
setTimeout(() => window.location.reload(), 1000);
}
}
};

run();
}, [navigate, searchParams]);

return (

Authenticating...
Please wait

);
};
Вещи, которые я уже пробовал, но не сработало:

Код: Выделить всё

Adding domain to the commonOptions

const commonOptions = {
path: "/",
sameSite: "None",
secure: true,
maxAge: 30 * 24 * 60 * 60 * 1000,
domain: isProd ? prodDomain : "localhost"
};

using sameSite Lax, Strict and None, as well as using lowercase for all 3 (lax, strict, none)

console logging the headers which showed:
'set-cookie': [
'authUser='
'authToken='
]
Я искал похожие вопросы, и люди говорят, что это потому, что они не установили домен или использовали неправильный сайт SameSite, но их решения просто не работают для меня.
Я также заметил, что при производстве прямо перед обновлением страницы в файлах cookie есть 4 файла cookie, по 2 набора каждого (authUser, authToken). Один из них - мой фактический домен, а другой - мой домен с точкой перед это. Я предполагаю, что браузер делает это автоматически, поскольку я не настраиваю домен.
на локальном хосте все это работает нормально, он устанавливает файлы cookie, и я могу нормально войти в систему.
на производстве он устанавливает файлы cookie, но как только страница обновляет оба файла cookie, набор серверных файлов автоматически удаляется.
Я могу получить данные из /sessions и просто настроить внешний интерфейс напрямую с помощью js-cookies, но я думаю это было бы менее безопасно, поскольку нельзя установить httpOnly

Подробнее здесь: https://stackoverflow.com/questions/798 ... ress-react
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»