API

Protected routes

Learn how to protect your API routes.

Hono has built-in support for middlewares, which are functions that can be used to modify the context or execute code before or after a route handler is executed.

That's how we can secure our API endpoints from unauthorized access. Below are some examples of you can leverage middlewares to protect your API routes.

Authenticated access

After validating the user's authentication status, we store their data in the context using Hono's built-in context. This allows us to access the user's information in subsequent middleware and procedures without having to re-validate the session.

Here's an example of middleware that validates whether the user is currently logged in and stores their data in the context:

middleware.ts
/**
 * Reusable middleware that enforces users are logged in before running the
 * procedure
 */
export const enforceAuth = createMiddleware<{
  Variables: {
    user: User;
  };
}>(async (c, next) => {
  const session = await auth.api.getSession({ headers: c.req.raw.headers });
  const user = session?.user ?? null;
 
  if (!user) {
    throw new HTTPException(HttpStatusCode.UNAUTHORIZED, {
      message: "You need to be logged in to access this feature!",
    });
  }
 
  c.set("user", user);
  await next();
});

Then we can use our defined middleware to protect endpoints by adding it before the route handler:

billing.router.ts
export const billingRouter = new Hono().get(
  "/customer",
  enforceAuth,
  async (c) => c.json(await getCustomerByUserId(c.var.user.id)),
);

Feature-based access

When developing your API you may want to restrict access to certain features based on the user's current subscription plan. (e.g. only users with "Pro" plan can access teams).

You can achieve this by creating a middleware that will check if the user has access to the feature and then pass the execution to the next middleware or procedure:

middleware.ts
/**
 * Reusable middleware that enforces users have access to a feature
 * before running the procedure
 */
export const enforceFeatureAvailable = (feature: Feature) =>
  createMiddleware<{
    Variables: {
      user: User;
    };
  }>(async (c, next) => {
    const { data: customer } = await getCustomerById(c.var.user.id);
 
    const hasFeature = isFeatureAvailable(customer, feature);
 
    if (!hasFeature) {
      throw new HTTPException(HttpStatusCode.PAYMENT_REQUIRED, {
        message: "Upgrade your plan to access this feature!",
      });
    }
 
    await next();
  });

Use it within your procedure the same way as we did with enforceUserIsAuthed middleware:

teams.router.ts
export const teamsRouter = new Hono().get(
  "/",
  enforceAuth,
  enforceFeatureAvailable(FEATURES.PRO.TEAMS),
  (c) => c.json(...),
);

These are just examples of what you can achieve with Hono middlewares. You can use them to add any kind of logic to your API (e.g. logging, caching, etc.)

Last updated on

On this page

Ship your startup everywhere. In minutes.