Race condition

i have a login page with a login action like this:
const login = action(async (formData: FormData) => {
("use server");
const username = formData.get("username");
const password = formData.get("password");
if (typeof username === "string" && typeof password === "string") {
const foundUser = await db.query.user.findFirst({
where: eq(user.username, username),
});

if (!foundUser || !(await verify(foundUser.password, password)))
return new Error("Wrong username or password");

const session = await lucia.createSession(foundUser.id, {});
const sessionCookie = lucia.createSessionCookie(session.id);

setCookie(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes
);
// this is happening before the cookie gets set
throw redirect("/");
}
}, "login");
const login = action(async (formData: FormData) => {
("use server");
const username = formData.get("username");
const password = formData.get("password");
if (typeof username === "string" && typeof password === "string") {
const foundUser = await db.query.user.findFirst({
where: eq(user.username, username),
});

if (!foundUser || !(await verify(foundUser.password, password)))
return new Error("Wrong username or password");

const session = await lucia.createSession(foundUser.id, {});
const sessionCookie = lucia.createSessionCookie(session.id);

setCookie(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes
);
// this is happening before the cookie gets set
throw redirect("/");
}
}, "login");
and an index page that checks the user:
const getUser = cache(async () => {
"use server";

const sessionId = getCookie(lucia.sessionCookieName);

if (!sessionId) throw redirect("/login");
const { user } = await lucia.validateSession(sessionId);

if (!user) throw redirect("/login");

return user;
}, "user");

export const route = {
load: () => getUser(),
};
const getUser = cache(async () => {
"use server";

const sessionId = getCookie(lucia.sessionCookieName);

if (!sessionId) throw redirect("/login");
const { user } = await lucia.validateSession(sessionId);

if (!user) throw redirect("/login");

return user;
}, "user");

export const route = {
load: () => getUser(),
};
when /login redirects to / after submitting the action, somehow / doesn't have the new cookie.
6 Replies
Hussein
Hussein5w ago
even when doing this it still doesn't work:
const login = action(async (formData: FormData) => {
("use server");
const username = formData.get("username");
const password = formData.get("password");
if (typeof username === "string" && typeof password === "string") {
const foundUser = await db.query.user.findFirst({
where: eq(user.username, username),
});

if (!foundUser || !(await verify(foundUser.password, password)))
return new Error("Wrong username or password");

const session = await lucia.createSession(foundUser.id, {});
const sessionCookie = lucia.createSessionCookie(session.id);

setCookie(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes
);
await new Promise((r) => setTimeout(1000, r));
throw redirect("/");
}
}, "login");
const login = action(async (formData: FormData) => {
("use server");
const username = formData.get("username");
const password = formData.get("password");
if (typeof username === "string" && typeof password === "string") {
const foundUser = await db.query.user.findFirst({
where: eq(user.username, username),
});

if (!foundUser || !(await verify(foundUser.password, password)))
return new Error("Wrong username or password");

const session = await lucia.createSession(foundUser.id, {});
const sessionCookie = lucia.createSessionCookie(session.id);

setCookie(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes
);
await new Promise((r) => setTimeout(1000, r));
throw redirect("/");
}
}, "login");
Alex Lohr
Alex Lohr5w ago
It seems the cookie is set after the page response is sent, so it cannot be set for the redirect. The usual pattern is to store a token in localStorage and add it to requests as a header.
Hussein
Hussein5w ago
so there's no way to fix it without using localStorage?
Alex Lohr
Alex Lohr5w ago
Not that I would know of.
Hussein
Hussein5w ago
fixed by changing some of the codebase without using localStorage tho so, this issue is completed
AlexErrant
AlexErrant4w ago
@Hussein can you retry with
throw redirect("/", { revalidate: "someWords" });
throw redirect("/", { revalidate: "someWords" });
if your action is using SingleFlightMutations I've been noticing cookies don't get used on the rendered response
Want results from more Discord servers?
Add your server