Derock
Derock9mo ago

How to set cookies in trpc response?

I have an app dir project that was created using this t3-app PR. On the client I have a form and I am using the trpc react client:
import { api } from "~/trpc/react";
[...]
const login = api.auth.login.useMutation({ ... });
import { api } from "~/trpc/react";
[...]
const login = api.auth.login.useMutation({ ... });
and I have the following route defined:
import { cookies } from "next/headers";

publicProcedure
.input(...)
.mutation(async ({ ctx, input }) => {
[...]

// somehow set a cookie
cookies().set("session", session.data.token, {
httpOnly: true,
});

[...]
}),
import { cookies } from "next/headers";

publicProcedure
.input(...)
.mutation(async ({ ctx, input }) => {
[...]

// somehow set a cookie
cookies().set("session", session.data.token, {
httpOnly: true,
});

[...]
}),
This does not set the cookie though -- no Set-Cookie header is in the response. I have no idea how to access the response manually to add the header in either.
7 Replies
Zeryther
Zeryther8mo ago
@Derock were you able to find a solution? I'm running into the same problem
Nick
Nick8mo ago
You can put the adapter's req/res into Context and use it directly or wrap it in an abstraction. But the dogmatic answer is "don't", tRPC isn't a REST framework and so wants to pull you away from HTTP/Browser stuff. It's not really the best tool to build an auth system with and works best when you have separate auth and can just pass tRPC a bearer token, like with OpenID-based auth
DxD
DxD8mo ago
@Derock I have the same issue For 3 days I tried
Derock
Derock8mo ago
i have a solution but i am currently in a class. i will let you know how i fixed it later today
DxD
DxD8mo ago
@Derock you saved token in cookie ? Nice…with that I can create the refresh token middleware and auth works I am happy to find you solution @Derock
Derock
Derock8mo ago
@Zeryther / @DxD My solution was the following: inside of the route handler for TRPC, I passed the response headers:
// src/app/api/trpc/trpc/[trpc]
const handler = (req: NextRequest) =>
fetchRequestHandler({
endpoint: "/api/trpc",
req,
router: appRouter,
- createContext: () => createTRPCContext
+ createContext: ({ resHeaders }) => createTRPCContext({ req, resHeaders }),
});
// src/app/api/trpc/trpc/[trpc]
const handler = (req: NextRequest) =>
fetchRequestHandler({
endpoint: "/api/trpc",
req,
router: appRouter,
- createContext: () => createTRPCContext
+ createContext: ({ resHeaders }) => createTRPCContext({ req, resHeaders }),
});
and then updated createTRPCContext to store the resHeaders in the context, and in my tRPC routes I was able to access that and set the cookie using
ctx.resHeaders.set("Set-Cookie", `sessionToken=${token}; Expires=${expire.toUTCString()}; Path=/; HttpOnly; SameSite=Strict`);
ctx.resHeaders.set("Set-Cookie", `sessionToken=${token}; Expires=${expire.toUTCString()}; Path=/; HttpOnly; SameSite=Strict`);
Lastly, the template I used (t3-app) uses unstable_httpBatchStreamLink by default. Setting headers is not supported in this, so I had to use a splitLink so that my auth requests would use httpLink instead.
DxD
DxD8mo ago
And works ?