Integrating tRPC with React Query and Auth
Configure tRPC's React Query integration, add authentication headers, and handle protected procedures.
Integrating tRPC with React Query and Auth is a free React Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
tRPC Context: Per-Request Data
The tRPC context is an object created fresh for every request by the createTRPCContext function. It can contain the database client, the authenticated session, the request headers, or any per-request data your procedures need.
Context creation runs before any procedure, making it the right place for authentication and database connection setup.
Adding Session to Context via NextAuth
In createTRPCContext, call getServerSession(authOptions) from next-auth/next. Attach the result to the context object: return { session: await getServerSession(authOptions), db }. All procedures now have access to ctx.session.
If session is null, the user is unauthenticated. Procedures can check this to conditionally return data or throw an error.
Creating a Protected Procedure
Define a middleware that checks ctx.session: const isAuthenticated = t.middleware(({ ctx, next }) => { if (!ctx.session) throw new TRPCError({ code: 'UNAUTHORIZED' }); return next({ ctx: { session: ctx.session } }); }).
The next() call passes the narrowed context (non-null session) to subsequent middlewares and the procedure handler.
protectedProcedure Definition
Compose the middleware with publicProcedure: const protectedProcedure = publicProcedure.use(isAuthenticated). Now any handler defined with protectedProcedure.query() or protectedProcedure.mutation() automatically has a non-null session in ctx.
TypeScript infers that ctx.session is non-null inside protected procedures because the middleware would have thrown before reaching the handler.
Using protectedProcedure
Replace publicProcedure with protectedProcedure for endpoints that require authentication: protectedProcedure.query(({ ctx }) => getProfileFor(ctx.session.user.id)). TypeScript knows ctx.session is non-null here, so accessing ctx.session.user.id is safe without a null check.
Unauthenticated requests automatically receive a 401 UNAUTHORIZED response before the handler executes.
Sending Auth Headers from the Client
Pass a headers function to httpBatchLink: links: [httpBatchLink({ url: '/api/trpc', headers: async () => { const token = await getToken(); return { Authorization: 'Bearer ' + token }; } })]. The function runs before every batch of requests.
This is used when authenticating tRPC from a React Native client or any non-Next.js client that manages its own auth tokens.
Server-Side Rendering with createServerSideHelpers
For SSR in the Next.js Pages Router, create a server-side helper: createServerSideHelpers({ router: appRouter, ctx: await createContext({ req, res }) }). Use helpers.post.getAll.prefetch() in getServerSideProps.
Dehydrate the prefetched state with dehydrate(queryClient) and pass it as props. On the client, the QueryClient hydrates from this state, avoiding the first-load refetch.
Hydrating tRPC Query Cache for SSR
Wrap your Next.js _app.tsx with Hydrate from @tanstack/react-query. Pass pageProps.trpcState to the state prop. This restores the prefetched query cache on the client from the serialized server state.
With this setup, users see fully populated pages immediately without client-side loading spinners on initial navigation.
TRPCError Codes
Throw TRPCError with appropriate HTTP-semantic codes: UNAUTHORIZED (401), FORBIDDEN (403), NOT_FOUND (404), BAD_REQUEST (400), INTERNAL_SERVER_ERROR (500). The tRPC client maps these to appropriate error states in the hook result.
The message field can contain user-facing details, but avoid leaking sensitive server information in production error messages.
tRPC with React Native
tRPC works with React Native clients using the same AppRouter type. Replace httpBatchLink with an httpLink (RN fetch works the same) and configure authentication headers. The @trpc/react-query adapter works identically to the web setup.
This means a monorepo can share one tRPC router between a Next.js web app and an Expo React Native app, with full type safety on both.
Role-Based Authorization
Extend the middleware pattern for role-based access: check ctx.session.user.role and throw TRPCError({ code: 'FORBIDDEN' }) if the role is insufficient. Create adminProcedure = publicProcedure.use(isAdmin) for admin-only endpoints.
Stack multiple middlewares for complex authorization: publicProcedure.use(isAuthenticated).use(hasFeatureFlag('beta')).query(...).
tRPC Protected Procedure
How is a protected procedure created in tRPC to enforce authentication?
Lesson Recap
tRPC context is created per-request and holds the session, database client, and other request-scoped data. Protected procedures are created by composing a session-checking middleware onto publicProcedure with .use(). Server-side rendering uses createServerSideHelpers for prefetching and Hydrate for cache restoration on the client.
Auth headers for non-Next.js clients are passed via the headers option on httpBatchLink.
Frequently asked questions
Is the “Integrating tRPC with React Query and Auth” lesson free?
Yes — the full text of “Integrating tRPC with React Query and Auth” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.
What will I learn in “Integrating tRPC with React Query and Auth”?
Configure tRPC's React Query integration, add authentication headers, and handle protected procedures. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start React Academy?
No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Integrating tRPC with React Query and Auth” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this React Academy lesson?
Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The Problem tRPC Solves
- Setting Up tRPC with React and Next.js
- Queries, Mutations, and Subscriptions
- Integrating tRPC with React Query and Auth