Cant manually set cookie using authClient on the server

So first up to make sense of the title. i have a sveltekit app and a hono app. hono has my auth instance and sveltekit only has access to the authClient. Now i have a bit of a special login where i need the user to fill in something and on the server we add some parts to the username basically. Im not sure why my approach dosent work because: 1) the signIn function works fine and returns success with data 2) I can set the cookie through sveltekit just fine 3) The auth setup itself also works. i have another login page where i directly call the authClient Signin methods on the client and there everything works fine! BUT getSession returns me user: null session: null So i feel like im either missing something or the cookie i manually set is somehow broken. also let me show the values between the set-cookie header i get on succes vs the thing i parse out of it set-cookie: name.session_token=jItmNnCgdeLOpqJ6NHv6DzKG5rit62hp.Fz%2FVmX2%2BgqRgYSYz4NfO%2FiVoZC9c32OEjC2fxbRv3gY%3D; Max-Age=604800; Domain=.localhost; Path=/; HttpOnly; SameSite=Lax parsedCookie:
{
"cookieName":"name.session_token",
"cookieValue":"jItmNnCgdeLOpqJ6NHv6DzKG5rit62hp.Fz%2FVmX2%2BgqRgYSYz4NfO%2FiVoZC9c32OEjC2fxbRv3gY%3D",
"options":{
"path":"/",
"maxAge":604800,
"domain":".localhost",
"httpOnly":true,
"sameSite":"lax"
}
}
{
"cookieName":"name.session_token",
"cookieValue":"jItmNnCgdeLOpqJ6NHv6DzKG5rit62hp.Fz%2FVmX2%2BgqRgYSYz4NfO%2FiVoZC9c32OEjC2fxbRv3gY%3D",
"options":{
"path":"/",
"maxAge":604800,
"domain":".localhost",
"httpOnly":true,
"sameSite":"lax"
}
}
i compared the cookies in the browser. they are the exact same Here is the code:
let cookie: string | null = null;
await authClient.signIn.email(
{
email: dummyMail,
password: form.data.pin,
callbackURL: '/auth/callback'
},
{
onSuccess(context) {
cookie = context.response.headers.get('set-cookie');
}
}
);
if (!cookie) return message(form, 'Login failed', { status: 400 });
const { cookieName, cookieValue, options } = parseCookie(cookie);
cookies.set(cookieName, cookieValue, options);
let cookie: string | null = null;
await authClient.signIn.email(
{
email: dummyMail,
password: form.data.pin,
callbackURL: '/auth/callback'
},
{
onSuccess(context) {
cookie = context.response.headers.get('set-cookie');
}
}
);
if (!cookie) return message(form, 'Login failed', { status: 400 });
const { cookieName, cookieValue, options } = parseCookie(cookie);
cookies.set(cookieName, cookieValue, options);
import type { CookieSerializeOptions } from 'cookie';
interface ParsedCookie {
cookieName: string;
cookieValue: string;
options: CookieSerializeOptions & { path: string };
}

export const parseCookie = (cookieStr: string): ParsedCookie => {
const mainParts = cookieStr.split(';')[0].split('=');
const cookieName = mainParts[0].trim();
const cookieValue = mainParts.slice(1).join('=').trim(); // Handle values that might contain '='
const options: CookieSerializeOptions & { path: string } = {
path: '/' // Default path to ensure it's always present
};

const parts = cookieStr.split(';').slice(1);

parts.forEach((part) => {
const option = part.trim();
const equalIndex = option.indexOf('=');

if (equalIndex === -1) {
const key = option.trim();
if (key === 'HttpOnly') {
options.httpOnly = true;
} else if (key === 'Secure') {
options.secure = true;
}
} else {
const key = option.substring(0, equalIndex).trim();
const value = option.substring(equalIndex + 1).trim();

if (key === 'Max-Age') {
options.maxAge = parseInt(value, 10);
} else if (key === 'Domain') {
options.domain = value;
} else if (key === 'Path') {
options.path = value;
} else if (key === 'SameSite') {
if (value === 'Lax' || value === 'Strict' || value === 'None') {
options.sameSite = value.toLowerCase() as 'lax' | 'strict' | 'none';
}
}
}
});
return { cookieName, cookieValue, options };
};
import type { CookieSerializeOptions } from 'cookie';
interface ParsedCookie {
cookieName: string;
cookieValue: string;
options: CookieSerializeOptions & { path: string };
}

export const parseCookie = (cookieStr: string): ParsedCookie => {
const mainParts = cookieStr.split(';')[0].split('=');
const cookieName = mainParts[0].trim();
const cookieValue = mainParts.slice(1).join('=').trim(); // Handle values that might contain '='
const options: CookieSerializeOptions & { path: string } = {
path: '/' // Default path to ensure it's always present
};

const parts = cookieStr.split(';').slice(1);

parts.forEach((part) => {
const option = part.trim();
const equalIndex = option.indexOf('=');

if (equalIndex === -1) {
const key = option.trim();
if (key === 'HttpOnly') {
options.httpOnly = true;
} else if (key === 'Secure') {
options.secure = true;
}
} else {
const key = option.substring(0, equalIndex).trim();
const value = option.substring(equalIndex + 1).trim();

if (key === 'Max-Age') {
options.maxAge = parseInt(value, 10);
} else if (key === 'Domain') {
options.domain = value;
} else if (key === 'Path') {
options.path = value;
} else if (key === 'SameSite') {
if (value === 'Lax' || value === 'Strict' || value === 'None') {
options.sameSite = value.toLowerCase() as 'lax' | 'strict' | 'none';
}
}
}
});
return { cookieName, cookieValue, options };
};
5 Replies
Silvan
SilvanOP4mo ago
like i genuinely dont get it. for testing i moved the logic to the frontend part and there it works fine even the cookie i get is the exact same format does the signin function secretly send headers that wont make the function fail but will not return user data?
sebastian
sebastian4mo ago
This is happening in production? or in dev mode
Silvan
SilvanOP4mo ago
dev mode
sebastian
sebastian4mo ago
Why would you set the cookie manually tho? im also using hono as be and the authclient sets the cookies itself
Silvan
SilvanOP4mo ago
because im calling it on the server site of my sveltekit app (reasons dont really matter) i even tried taking the same headers as if the client would make the request but nope okay im mad i was missing a decodeURIComponent for the cookieValue ffs

Did you find this page helpful?