The createContext-function is called for each incoming request so here you can add contextual information about the calling user from the request object.
server/context.ts
ts
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'd might want to do in your ctx fn
async 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>;
// [..] Define API handler and app router
server/routers/_app.ts
ts
import * as trpc from '@trpc/server';
import { TRPCError } from '@trpc/server';
import { createRouter } from '../createRouter';
export const appRouter = createRouter()
// open for anyone
.query('hello', {
`input: z.string().nullish(),`
`resolve: (opts) => {`
``return `hello ${opts.input ?? opts.ctx.user?.name ?? 'world'}`;``
`},`
})
// checked in resolver
.query('secret', {
`resolve: (opts) => {`
`if (!opts.ctx.user) {`
`throw new TRPCError({ code: 'UNAUTHORIZED' });`
`}`
`return {`
`secret: 'sauce',`
`};`
`},`
});
Option 2: Authorize using middleware
server/routers/_app.ts
ts
import * as trpc from '@trpc/server';
import { TRPCError } from '@trpc/server';
import { createRouter } from '../createRouter';
export const appRouter = createRouter()
// this is accessible for everyone
.query('hello', {
`input: z.string().nullish(),`
`resolve: (opts) => {`
``return `hello ${opts.input ?? opts.ctx.user?.name ?? 'world'}`;``
`},`
})
.merge(
`'admin.',`
`createRouter()`
`// this protects all procedures defined next in this router`
`.middleware(async ({ ctx, next }) => {`
`if (!ctx.user?.isAdmin) {`
`throw new TRPCError({ code: 'UNAUTHORIZED' });`
`}`
`return next();`
`})`
`.query('secret', {`
`resolve: (opts) => {`
`return {`
`secret: 'sauce',`
`};`
`},`
`}),`
);
This middleware can be re-used for multiple sub-routers by creating a protected router helper.