Authorization
The createContext
function is called for each incoming request, so here you can add contextual information about the calling user from the request object.
Create context from request headers
server/context.tsts
import {getSession // Example function} from './somewhere/in/your/app/utils';import {FetchCreateContextFnOptions } from '@trpc/server/adapters/fetch';export async functioncreateContext (opts :FetchCreateContextFnOptions ) {// Create your context based on the request object// Will be available as `ctx` in all your resolversconstsession = awaitgetSession (opts .req );return {...opts ,session ,};}// This context will be available as `ctx` in all your resolversexport typeContext =Awaited <ReturnType <typeofcreateContext >>;
server/context.tsts
import {getSession // Example function} from './somewhere/in/your/app/utils';import {FetchCreateContextFnOptions } from '@trpc/server/adapters/fetch';export async functioncreateContext (opts :FetchCreateContextFnOptions ) {// Create your context based on the request object// Will be available as `ctx` in all your resolversconstsession = awaitgetSession (opts .req );return {...opts ,session ,};}// This context will be available as `ctx` in all your resolversexport typeContext =Awaited <ReturnType <typeofcreateContext >>;
Authorize using a base procedure (recommended)
server/trpc.tsts
import {initTRPC ,TRPCError } from '@trpc/server';import type {Context } from './context';constt =initTRPC .context <Context >().create ();export constrouter =t .router ;export constpublicProcedure =t .procedure ;// you can reuse this for any procedureexport constprotectedProcedure =publicProcedure .use (async functionisAuthed (opts ) {const {session } =opts .ctx // `session` is nullableif (!session ) {throw newTRPCError ({code : 'UNAUTHORIZED' });}returnopts .next ({ctx : {// ✅ session value is known to be non-null nowsession ,},});},);/// ....... ✨ usage in a procedure// @filename: server/routers/post.tsimport {publicProcedure ,protectedProcedure ,router } from '../trpc'import {z } from 'zod';export constpostRouter =router ({add :protectedProcedure .mutation (async (opts ) => {// ✨ session is non-nullable nowopts .ctx .session ;// [...]}),})
server/trpc.tsts
import {initTRPC ,TRPCError } from '@trpc/server';import type {Context } from './context';constt =initTRPC .context <Context >().create ();export constrouter =t .router ;export constpublicProcedure =t .procedure ;// you can reuse this for any procedureexport constprotectedProcedure =publicProcedure .use (async functionisAuthed (opts ) {const {session } =opts .ctx // `session` is nullableif (!session ) {throw newTRPCError ({code : 'UNAUTHORIZED' });}returnopts .next ({ctx : {// ✅ session value is known to be non-null nowsession ,},});},);/// ....... ✨ usage in a procedure// @filename: server/routers/post.tsimport {publicProcedure ,protectedProcedure ,router } from '../trpc'import {z } from 'zod';export constpostRouter =router ({add :protectedProcedure .mutation (async (opts ) => {// ✨ session is non-nullable nowopts .ctx .session ;// [...]}),})
Authorize in a resolver resolver
server/routers/_app.tsts
import { initTRPC, TRPCError } from '@trpc/server';import type { Context } from '../context';export const t = initTRPC.context<Context>().create();const appRouter = t.router({// open for anyonehello: t.procedure.input(z.string().nullish()).query((opts) =>`hello ${opts.input ?? opts.ctx.session?.user?.name ?? 'world'}`,),// checked in resolversecret: t.procedure.query((opts) => {if (!opts.ctx.session) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return {secret: 'sauce',};}),});
server/routers/_app.tsts
import { initTRPC, TRPCError } from '@trpc/server';import type { Context } from '../context';export const t = initTRPC.context<Context>().create();const appRouter = t.router({// open for anyonehello: t.procedure.input(z.string().nullish()).query((opts) =>`hello ${opts.input ?? opts.ctx.session?.user?.name ?? 'world'}`,),// checked in resolversecret: t.procedure.query((opts) => {if (!opts.ctx.session) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return {secret: 'sauce',};}),});