ianh.eth
ianh.eth7mo ago

How to pass through authentication header when using createTRPCProxyClient and RSC?

Hi - we are having a great time with tRPC, and have it working well in a Next14 + React Server Components environment. However, we're seeing that the headers aren't being passed through when a trpc query call is made from within a RSC component via await trcp.profile.me.query() I looked into trying to pass through the headers and there's no way to access the actual headers from the current request, only to add new ones via headers() function. What is the preferred way to pass through auth headers in a client => RSC => trpc.query => server environment?
7 Replies
BeBoRE
BeBoRE7mo ago
You need to pass the headers to your query client provider
ianh.eth
ianh.eth7mo ago
Sorry, I must have not been clear. This is for React Server Components, where the rendering occurs 100% on server. So the client implementation doesn't get touched, this is exclusively on the server side. We're currently using the proxy implementation, not the SSR implementation, but I'm unclear how to go from RSC context (req,res) and apply that req.headers.authorization to the proxy client, which is initialized elsewhere. It would be cumbersome to require each RSC component to pass an auth header, but I'm failing to see any other options here.
BeBoRE
BeBoRE7mo ago
Oh my bad, have you tried to use appRouter.createCaller and then pass in the context. You really shouldn't be using createProxyClient it just adds way too much overhead since you'll be doing http calls.
BeBoRE
BeBoRE7mo ago
Server Side Calls | tRPC
You may need to call your procedure(s) directly from the same server they're hosted in, router.createCaller() can be used to achieve this.
ianh.eth
ianh.eth7mo ago
You may need to call your procedure(s) directly from the same server they're hosted in
So - this would generally be the right solution, but our trpc server is not within the nextjs trpc webapp. We have multiple diff nextjs servers all proxying calls (via next.config.js rewrites) from web -> API server. So the flow sorta looks like this: browser =[auth cookie]=> vercel RSC (server action) =[proxy auth header]=> tRPC fastify server Really what I'm trying to figure out is how to add the auth header at the RSC step.
BeBoRE
BeBoRE7mo ago
Then you probably need something like this
/* eslint-disable @typescript-eslint/no-shadow */
import * as context from 'next/headers';
import {
createTRPCProxyClient,
loggerLink,
unstable_httpBatchStreamLink,
} from '@trpc/client';

import { AppRouter } from '@ei/trpc';

import { getApiUrl, transformer } from './shared';

export const api = createTRPCProxyClient<AppRouter>({
transformer,
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === 'development' ||
(op.direction === 'down' && op.result instanceof Error),
}),
unstable_httpBatchStreamLink({
url: getApiUrl(),
headers() {
const heads = new Map(context.headers());
heads.set('x-trpc-source', 'rsc');
return Object.fromEntries(heads);
},
}),
],
});
/* eslint-disable @typescript-eslint/no-shadow */
import * as context from 'next/headers';
import {
createTRPCProxyClient,
loggerLink,
unstable_httpBatchStreamLink,
} from '@trpc/client';

import { AppRouter } from '@ei/trpc';

import { getApiUrl, transformer } from './shared';

export const api = createTRPCProxyClient<AppRouter>({
transformer,
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === 'development' ||
(op.direction === 'down' && op.result instanceof Error),
}),
unstable_httpBatchStreamLink({
url: getApiUrl(),
headers() {
const heads = new Map(context.headers());
heads.set('x-trpc-source', 'rsc');
return Object.fromEntries(heads);
},
}),
],
});
I'll see if I can find a beter example