Writing because I did not find doc for setting clerk on the app router
Hey there! I was building an app using the T3 stack and decided to integrate the new auth provider clerk.io with t3 instead of nextAuth (which turned out to be a big mistake).
Unfortunately, it wasn't as developer-friendly as they claimed. (Only a few devs were harmed during the process.)
I encountered an issue when trying to add a clerk to trpc. I was following a clerk offical guide. The code provided works for a page router with trcp and not the app router.
/* server/context.ts */
import * as trpc from '@trpc/server'
import * as trpcNext from '@trpc/server/adapters/next'
import { getAuth } from '@clerk/nextjs/server'
export const createContext = async (opts: trpcNext.CreateNextContextOptions) => {
return { auth: getAuth(opts.req) }
}
export type Context = trpc.inferAsyncReturnType<typeof createContext>
In createContext definition,
CreateNextContextOptions is used to obtain the req, which is a pattern in the page router. At that time I did not know that. I tried to find different solutions but none worked
After a few thrilling adventures of TS Debugs of ...
- 🤸♂️ Type Gymnastics
- 🔍 Issue Hunting
- 💻 Blog Screening
and searching several Discord threads, I found something that works.
I'm using a completely new method from their updated API, which is not present in any older blogs. I hope they point out the correct way for the app router in the guides soon. Until then, try the following code.
/* server/trpc.ts */
import { currentUser } from "@clerk/nextjs";
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";
import { db } from "~/server/db";
export const createTRPCContext = async (opts: { headers: Headers }) => {
const user = await currentUser();
return {
db,
user,
...opts,
};
};
// check if the user is signed in, otherwise throw an UNAUTHORIZED code
const isAuthed = t.middleware(({ next, ctx }) => {
if (!ctx.user?.id) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
user: ctx.user,
},
});
});
export const protectedProcedure = publicProcedure.use(isAuthed);
It's taken from this the very long hybrid discord thread but it works.
Top comments (2)
<3
I also spend 3 days trying to figure this out, but I didnt.
Until I found this, thank you so much.
Hopefully Clerk gets added to the T3 Stack setup