MrJohz
MrJohz2w ago

How can I access the session in fastify when using `useWSS: true`?

I've got a fastify/trpc application that looks something like this:
await using app = Fastify({
loggerInstance: logger,
bodyLimit: 5 * 1024 * 1024,
https: stores.config.sslOptions ?? null,
maxParamLength: 5000,
});

app.register(ws);
app.register(fastifyCookie);
app.register(fastifySession, {
secret: "super secret, don't look at me",
});

function createContext({ req }: CreateFastifyContextOptions) {
console.log(req.session); // logs "undefined"
return {};
}

app.register(fastifyTRPCPlugin, {
prefix: "/trpc",
useWSS: true,
keepAlive: { enabled: true, pingMs: 50 * 1000 },
trpcOptions: { router, onError, createContext },
});
await using app = Fastify({
loggerInstance: logger,
bodyLimit: 5 * 1024 * 1024,
https: stores.config.sslOptions ?? null,
maxParamLength: 5000,
});

app.register(ws);
app.register(fastifyCookie);
app.register(fastifySession, {
secret: "super secret, don't look at me",
});

function createContext({ req }: CreateFastifyContextOptions) {
console.log(req.session); // logs "undefined"
return {};
}

app.register(fastifyTRPCPlugin, {
prefix: "/trpc",
useWSS: true,
keepAlive: { enabled: true, pingMs: 50 * 1000 },
trpcOptions: { router, onError, createContext },
});
I would expect that the req in the createContext function would have access to the session (and it does if useWSS is false). However, when using TRPC with websockets, it currently consistently logs undefined. I assume this is because I'm misconfiguring something somewhere, but I'm not sure what, and I'm not sure how to solve this. Has anyone experienced this, or does anyone have any suggestions about how to resolve this? Thanks in advance!
Solution:
Hi @Mr. Joker, I ended up writing my solution up on my blog, you can read that here: https://jonathan-frere.com/posts/trpc-fastify-websockets/ Specifically, the solution I found was this: ```typescript...
Accessing Fastify Sessions via tRPC Websockets | Jonathan's Blog
This is a quick post to point out a potential issue that might catch you out with using Fastify’s sessions mechanism alongside tRPC’s websockets transport, and how I’ve fixed it in my projects. The problem happens with an application that looks something like this: const app = Fastify(); app.register(ws); app.register(fastifyCookie); app.r...
Jump to solution
4 Replies
Mr. Joker
Mr. Joker6d ago
Hey, have you found solution for this? I have same problem with session undefined in created context in websocket subscriptions
MrJohz
MrJohzOP6d ago
I did. Basically, the type of req is wrong: for websockets, it's FastifyRequest | IncomingMessage where IncomingMessage is the raw node request object. To get hold of the FastifyRequest object, you can use a Fastify to listen to all incoming requests, and then save those requests in a WeakMap. Then in the context you can use the WeakMap to fetch the original requests out again. I'll write it up properly tomorrow.
Solution
MrJohz
MrJohz5d ago
Hi @Mr. Joker, I ended up writing my solution up on my blog, you can read that here: https://jonathan-frere.com/posts/trpc-fastify-websockets/ Specifically, the solution I found was this:
// create a new scope so that the hook we add later will only
// affect tRPC-specific requests
app.register((app) => {
// use a WeakMap to avoid leaking memory by holding on to
// requests longer than necessary
const REQS = new WeakMap<
FastifyRequest | IncomingMessage,
FastifyRequest
>();

app.addHook("onRequest", async (req) => {
// associate each raw `IncomingMessage` (`req.raw`) with
// the original `IncomingMessage`
REQS.set(req.raw, req);
});

app.register(fastifyTRPCPlugin, {
prefix: "/trpc",
useWSS: true,
trpcOptions: {
router,
onError,
createContext: ({ req }) => {
// given either a `FastifyRequest` or an
// `IncomingMessage`, fetch the related
// `FastifyRequest` that we saved earlier
const realReq = REQS.get(req.raw ?? req);
if (!realReq)
throw new Error("This should never happen");

console.log(realReq.session); // logs the session object
return {};
},
},
});
});
// create a new scope so that the hook we add later will only
// affect tRPC-specific requests
app.register((app) => {
// use a WeakMap to avoid leaking memory by holding on to
// requests longer than necessary
const REQS = new WeakMap<
FastifyRequest | IncomingMessage,
FastifyRequest
>();

app.addHook("onRequest", async (req) => {
// associate each raw `IncomingMessage` (`req.raw`) with
// the original `IncomingMessage`
REQS.set(req.raw, req);
});

app.register(fastifyTRPCPlugin, {
prefix: "/trpc",
useWSS: true,
trpcOptions: {
router,
onError,
createContext: ({ req }) => {
// given either a `FastifyRequest` or an
// `IncomingMessage`, fetch the related
// `FastifyRequest` that we saved earlier
const realReq = REQS.get(req.raw ?? req);
if (!realReq)
throw new Error("This should never happen");

console.log(realReq.session); // logs the session object
return {};
},
},
});
});
Accessing Fastify Sessions via tRPC Websockets | Jonathan's Blog
This is a quick post to point out a potential issue that might catch you out with using Fastify’s sessions mechanism alongside tRPC’s websockets transport, and how I’ve fixed it in my projects. The problem happens with an application that looks something like this: const app = Fastify(); app.register(ws); app.register(fastifyCookie); app.r...
Mr. Joker
Mr. Joker5d ago
Thank you very much for the information

Did you find this page helpful?