Skip to content

Hono adapter

The optional adapter at rolebook/middleware/hono resolves a bound authorization context and a concrete resource request for each route, and maps denials to 403.

import { Hono } from "hono";
import { createRolebookMiddleware, type RolebookEnv } from "rolebook/middleware/hono";
const app = new Hono<RolebookEnv<typeof policy>>();
const middleware = createRolebookMiddleware({
policy,
getBinding: async (c) => loadAuthorizationContext(c), // { subject, assignments, context? }
});
app.onError(middleware.onError);
app.get(
"/projects/:id",
middleware.requirePermission(async (c) => ({
permission: "project:read",
resource: await loadTrustedProject(c.req.param("id")),
})),
(c) => c.json({ ok: true }),
);
  • getBinding returns the subject and assignments for the request, or undefined for an unauthenticated request, which becomes 401.
  • requirePermission takes a loader that returns the permission and trusted resource for the route. A denial becomes 403. The bound authorizer is also available on the context as authorization for further checks in the handler.
  • app.onError(middleware.onError) is required if downstream enforce() denials in handlers should become 403 responses. Without it, Hono returns its normal 500. The handler preserves Hono HTTPException responses and logs unrelated errors before a generic 500.
Option Purpose
onUnauthorized, onForbidden Replace the default 401 and 403 responses.
onInternalError Report unexpected downstream errors before the generic 500. Defaults to console.error.
onEvaluationFault Report evaluator faults. Passed straight to createAuthorizer.

Parameterize RolebookEnv with the policy type so handlers keep the concrete permission union. Adapters contain no policy logic.