How to make prefetching/RSC suspense work with auth?

Hi πŸ‘‹ I'm using the rsc-rq-prefetch pattern in my project. It worked quite well - up until I added auth to my tRPC procedures. During SSR a server error gets thrown because the useSuspenseQuery request fails (there's no auth because SSR does not use the request's context/headers https://github.com/vercel/next.js/discussions/60640). I'm wondering if there's a workaround that allows prefetching on the server for auth-protected procedures. Am I missing something obvious? I've seen the rsc-links example... Maybe I could make use of this? There it seems the server can use the request headers in a procedure. But since it should be a prefetch (and if pending, should be streamed in later) I'm not sure how I can pass such a rsc-linked call to the client in a possible pending state.
1 Reply
인택
인택‒3w ago
You can still access the headers getter. Parse headers, you can also extract cookies from it. Here's my code creating context in SSR env with Next-Auth.
export const createTRPCContext = cache(async (opts?: FetchCreateContextFnOptions) => {
const session = await getServerSession(authOptions)

const IS_SSR = !opts

if (IS_SSR) {
const h = await headers()

const cookieHeader = h.get('cookie') || ''
const cookies: Record<string, string> = {}
cookieHeader.split(';').forEach((cookie) => {
const [name, ...rest] = cookie.trim().split('=')
if (name) cookies[name] = rest.join('=')
})

const sessionToken =
process.env.NODE_ENV === 'production'
? cookies['__Secure-next-auth.session-token']
: cookies['next-auth.session-token']

const decodedJWT = await decode({
secret: process.env.NEXTAUTH_SECRET || '',
token: sessionToken,
})

return {
session,
clientIp: getClientIp(h),
authCode: decodedJWT?.auth_code || null,
}
}

...
}
export const createTRPCContext = cache(async (opts?: FetchCreateContextFnOptions) => {
const session = await getServerSession(authOptions)

const IS_SSR = !opts

if (IS_SSR) {
const h = await headers()

const cookieHeader = h.get('cookie') || ''
const cookies: Record<string, string> = {}
cookieHeader.split(';').forEach((cookie) => {
const [name, ...rest] = cookie.trim().split('=')
if (name) cookies[name] = rest.join('=')
})

const sessionToken =
process.env.NODE_ENV === 'production'
? cookies['__Secure-next-auth.session-token']
: cookies['next-auth.session-token']

const decodedJWT = await decode({
secret: process.env.NEXTAUTH_SECRET || '',
token: sessionToken,
})

return {
session,
clientIp: getClientIp(h),
authCode: decodedJWT?.auth_code || null,
}
}

...
}

Did you find this page helpful?