Auth Middleware
Routes can carry an auth middleware. The REST handler awaits it and returns
403 when it fails. This is a deliberate security guarantee.
Define an authenticated route
Section titled “Define an authenticated route”router.get("/users/me", { plan: db.from(users).where("id", "=", (ctx) => ctx.userId)._plan, auth: async (req) => { const token = req.headers.authorization?.replace("Bearer ", ""); if (!token) return false; const r = await auth.authenticate(token); return r.ok; // true = allowed },});The handler awaits it
Section titled “The handler awaits it”const out = await handle(restReq);if ("status" in out && out.status === 403) { return res.status(403).json(out.body); // { error: "Forbidden" }}If auth throws or returns false, the handler short-circuits with 403. The
request never reaches the query.
Pair with RLS
Section titled “Pair with RLS”For row-level scoping, combine route auth with an RLS policy:
const scoped = applyPolicy(db.from(files), allowOwner("ownerId"), ctx);router.get("/files", { plan: scoped._plan, auth: requireUser });Best practices
Section titled “Best practices”- Return
false(not throw) for “not authorized” — reserve throws for errors. - Combine auth middleware with RLS for defense in depth.
- Centralize auth in one middleware factory and reuse it.
Common mistakes
Section titled “Common mistakes”- Forgetting to
awaitthe handler — auth runs too late. - Only checking auth in handlers, not at the route level.
Related
Section titled “Related”- REST Handler — where auth is invoked.
- RLS Policy DSL — row-level scoping.
