DEV Community

Cover image for Configuring Clerk.io on t3 with tRPC
The Sword Breaker
The Sword Breaker

Posted on

Configuring Clerk.io on t3 with tRPC

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).

Clrek

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>


Enter fullscreen mode Exit fullscreen mode

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,
  };
};


Enter fullscreen mode Exit fullscreen mode



// 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);



Enter fullscreen mode Exit fullscreen mode

It's taken from this the very long hybrid discord thread but it works.

Top comments (0)