Authentication
Authentication in Covenant happens in the contextGenerator — a function that runs on every request and returns per-request context available to all procedures.
NextAuth example
Section titled “NextAuth example”With NextAuth v5:
import { auth } from "@/auth"; // your NextAuth configimport { CovenantServer } from "@covenant-rpc/server";import { emptyServerToSidekick } from "@covenant-rpc/server/interfaces/empty";import { covenant } from "./covenant";
export const server = new CovenantServer(covenant, { contextGenerator: async ({ request }) => { const session = await auth.api.getSession({ headers: request.headers }); return { user: session?.user ?? null }; }, derivation: ({ ctx, error }) => ({ requireUser: () => { if (!ctx.user) error("Unauthorized", 401); return ctx.user!; }, }), sidekickConnection: emptyServerToSidekick(),});Using auth in procedures
Section titled “Using auth in procedures”server.defineProcedure("getMyProfile", { resources: ({ ctx }) => ctx.user ? [`user/${ctx.user.id}`] : [], procedure: ({ derived }) => { const user = derived.requireUser(); // throws 401 if not logged in return db.getUserProfile(user.id); },});requireUser() uses the error() function, which throws immediately and never returns — TypeScript correctly narrows the type after the call.
Bearer token auth
Section titled “Bearer token auth”For API clients using bearer tokens:
contextGenerator: async ({ request }) => { const authorization = request.headers.get("Authorization"); const token = authorization?.replace("Bearer ", ""); if (!token) return { userId: null };
const userId = await verifyJwt(token); return { userId };},Pass the token from the client:
export const client = new CovenantClient(covenant, { serverConnection: httpClientToServer("/api/covenant", { Authorization: `Bearer ${token}`, }), sidekickConnection: emptyClientToSidekick(),});Role-based access
Section titled “Role-based access”Extend the derivation pattern for roles:
derivation: ({ ctx, error }) => ({ requireUser: () => { if (!ctx.user) error("Unauthorized", 401); return ctx.user!; }, requireAdmin: () => { if (!ctx.user) error("Unauthorized", 401); if (ctx.user.role !== "admin") error("Forbidden", 403); return ctx.user!; },}),