T
TanStack3mo ago
fair-rose

tRPC + Custom Auth

Hi again! I was hoping someone could help with a cookie problem I have. I'm pretty new to the world of SSR (I think SSR is where my issue lies, please correct if I'm wrong). I was looking through https://github.com/makyinmars/tan-stack-start-full-stack/?tab=readme-ov-file#tan-stack-start-full-stack for custom auth, which is pretty similar to what I've used with NextJS previously, it follows the Lucia guide for rolling your own auth service. Anyways, I have a function which creates a token and a session but when I try to set a cookie, I get the following error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client. I'm using setCookie from vinxi/http, also tried with setCookie from @tanstack/react-start/server. Here's the function that's throwing the error:
export async function setSessionTokenCookie(
token: string,
expiresAt: Date
): Promise<void> {
setCookie(SESSION_COOKIE_NAME, token, {
httpOnly: true,
sameSite: 'lax',
secure: env.NODE_ENV === 'production',
expires: expiresAt,
path: '/',
});
}
export async function setSessionTokenCookie(
token: string,
expiresAt: Date
): Promise<void> {
setCookie(SESSION_COOKIE_NAME, token, {
httpOnly: true,
sameSite: 'lax',
secure: env.NODE_ENV === 'production',
expires: expiresAt,
path: '/',
});
}
This is being call inside my trpc mutation. Let me know if I need to share anything else and thanks in advance.
GitHub
GitHub - makyinmars/tan-stack-start-full-stack
Contribute to makyinmars/tan-stack-start-full-stack development by creating an account on GitHub.
5 Replies
fair-rose
fair-roseOP3mo ago
Update I recall having a similar problem in NextJS now, it was due to using httpBatchStreamLink in the createTRPCClient func. Replacing it with httpBatchLink solves the cookie setting problem. Is there a world where I have use streaming and still set the cookie from a tRPC mutation?
sunny-green
sunny-green3mo ago
You should either do it in the procedure itself or you should use a server function to set the cookie
fair-rose
fair-roseOP3mo ago
I tried calling setSessionTokenCookie in the procudure, before the final return but that's what returned the error. If I were to use a server function, would the server fn first call the procedure then set the cookie once the procedure has resolved?
sunny-green
sunny-green3mo ago
i believe you can either just use trpc procedures or server functions but not both combine, using server fn:
const createSignInFn = createServerFn({
method: "POST",
})
.validator(signInSchema)
.handler(async ({ data }) => {
const validResult = signInSchema.safeParse(data);
if (!validResult.success) {
throw new Error(validResult.error.message);
}

const { username, password } = validResult.data;

await rateLimitByKey({ key: username, limit: 3, window: 10000 });
const user = await signInUseCase(username, password);

await setSession(user.id);
return {
isRedirect: true,
};
});
const createSignInFn = createServerFn({
method: "POST",
})
.validator(signInSchema)
.handler(async ({ data }) => {
const validResult = signInSchema.safeParse(data);
if (!validResult.success) {
throw new Error(validResult.error.message);
}

const { username, password } = validResult.data;

await rateLimitByKey({ key: username, limit: 3, window: 10000 });
const user = await signInUseCase(username, password);

await setSession(user.id);
return {
isRedirect: true,
};
});
I would suggest that you should add the session in the trpc context
fair-rose
fair-roseOP3mo ago
I'll give the server function a try since the procedure throws an error and I'll be back to report my findings

Did you find this page helpful?