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 * as trpc from '@trpc/server';import { inferAsyncReturnType } from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';import { decodeAndVerifyJwtToken } from './somewhere/in/your/app/utils';export async function createContext({req,res,}: trpcNext.CreateNextContextOptions) {// Create your context based on the request object// Will be available as `ctx` in all your resolvers// This is just an example of something you might want to do in your ctx fnasync function getUserFromHeader() {if (req.headers.authorization) {const user = await decodeAndVerifyJwtToken(req.headers.authorization.split(' ')[1],);return user;}return null;}const user = await getUserFromHeader();return {user,};}type Context = inferAsyncReturnType<typeof createContext>;
server/context.tsts
import * as trpc from '@trpc/server';import { inferAsyncReturnType } from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';import { decodeAndVerifyJwtToken } from './somewhere/in/your/app/utils';export async function createContext({req,res,}: trpcNext.CreateNextContextOptions) {// Create your context based on the request object// Will be available as `ctx` in all your resolvers// This is just an example of something you might want to do in your ctx fnasync function getUserFromHeader() {if (req.headers.authorization) {const user = await decodeAndVerifyJwtToken(req.headers.authorization.split(' ')[1],);return user;}return null;}const user = await getUserFromHeader();return {user,};}type Context = inferAsyncReturnType<typeof createContext>;
Option 1: Authorize using resolver​
server/routers/_app.tsts
import { TRPCError, initTRPC } from '@trpc/server';import { Context } from '../context';export const t = initTRPC.context<Context>().create();const appRouter = t.router({// open for anyonehello: t.procedure.input(z.string().nullish()).query(({ input, ctx }) => `hello ${input ?? ctx.user?.name ?? 'world'}`),// checked in resolversecret: t.procedure.query(({ ctx }) => {if (!ctx.user) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return {secret: 'sauce',};}),});
server/routers/_app.tsts
import { TRPCError, initTRPC } from '@trpc/server';import { Context } from '../context';export const t = initTRPC.context<Context>().create();const appRouter = t.router({// open for anyonehello: t.procedure.input(z.string().nullish()).query(({ input, ctx }) => `hello ${input ?? ctx.user?.name ?? 'world'}`),// checked in resolversecret: t.procedure.query(({ ctx }) => {if (!ctx.user) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return {secret: 'sauce',};}),});
Option 2: Authorize using middleware​
server/routers/_app.tsts
import { TRPCError, initTRPC } from '@trpc/server';export const t = initTRPC.context<Context>().create();const isAuthed = t.middleware(({ next, ctx }) => {if (!ctx.user?.isAdmin) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return next({ctx: {user: ctx.user,},});});// you can reuse this for any procedureexport const protectedProcedure = t.procedure.use(isAuthed);t.router({// this is accessible for everyonehello: t.procedure.input(z.string().nullish()).query(({ input, ctx }) => `hello ${input ?? ctx.user?.name ?? 'world'}`),admin: t.router({// this is accessible only to adminssecret: protectedProcedure.query(({ ctx }) => {return {secret: 'sauce',};}),}),});
server/routers/_app.tsts
import { TRPCError, initTRPC } from '@trpc/server';export const t = initTRPC.context<Context>().create();const isAuthed = t.middleware(({ next, ctx }) => {if (!ctx.user?.isAdmin) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return next({ctx: {user: ctx.user,},});});// you can reuse this for any procedureexport const protectedProcedure = t.procedure.use(isAuthed);t.router({// this is accessible for everyonehello: t.procedure.input(z.string().nullish()).query(({ input, ctx }) => `hello ${input ?? ctx.user?.name ?? 'world'}`),admin: t.router({// this is accessible only to adminssecret: protectedProcedure.query(({ ctx }) => {return {secret: 'sauce',};}),}),});