TurboJet
API

Protect API endpoints

Public routes, optional session, requireAuth, requireAdmin, and rate limits.

TurboJet does not use oRPC-style publicProcedure / protectedProcedure. Protection is ordinary Hono middleware composed on each route.

Patterns

PatternHow
PublicNo auth middleware (e.g. feedback POST /)
Optional sessionCall getSessionFromHeaders inside the handler
AuthenticatedrequireAuth → c.get("session")
AdminrequireAuth then requireAdmin (role ADMIN)

Public + optional session

Feedback is public but can attach a signed-in user when cookies are present:

packages/api/src/modules/feedback/router.ts
export const feedbackRouter = new Hono().post(
	"/",
	rateLimit("WRITE"),
	zValidator("json", createFeedbackSchema),
	async (c) => {
		const session = await getSessionFromHeaders(c.req.raw.headers);
		const result = await createFeedback({
			data: c.req.valid("json"),
			session,
			ipAddress: c.req.header("x-forwarded-for") ?? null,
		});
		return c.json(result);
	},
);

getSessionFromHeaders returns null for guests — it does not reject the request.

Authenticated (requireAuth)

Use requireAuth so unauthenticated callers get 401. Typed routers use Hono<AuthEnv> so c.get("session") is available:

packages/api/src/modules/me/router.ts
import { requireAuth, type AuthEnv } from "../../middleware/auth";

export const meRouter = new Hono<AuthEnv>().patch(
	"/name",
	rateLimit("WRITE"),
	requireAuth,
	zValidator("json", changeNameSchema),
	async (c) => {
		const session = c.get("session");
		const result = await changeName(session.user.id, c.req.valid("json"));
		return c.json(result);
	},
);

Admin (requireAuth + requireAdmin)

Admin routes chain both middleware. Spreading a shared guard keeps the order consistent:

packages/api/src/modules/admin/router.ts
import { requireAuth, type AuthEnv } from "../../middleware/auth";
import { requireAdmin } from "../../middleware/admin";

const adminGuard = [rateLimit("READ"), requireAuth, requireAdmin] as const;
const adminWriteGuard = [rateLimit("WRITE"), requireAuth, requireAdmin] as const;

const usersRouter = new Hono<AuthEnv>().get(
	"/",
	...adminGuard,
	zValidator("query", usersListInputSchema),
	async (c) => {
		const result = await getUsersList(c.req.valid("query"));
		return c.json(result);
	},
);

requireAdmin checks that the session user has role ADMIN.

Custom middleware

Compose additional Hono middleware the same way — before or after auth as needed. There is no Permix / org-procedure layer in this kit.

Rate limiting

Almost every route should use rateLimit("READ" | "WRITE" | …) early in the chain. Buckets and limits live in packages/api/src/middleware/rate-limit.ts and packages/api/src/lib/ratelimit.ts.

On this page