Skip to main content

Protected 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 using next-auth, it automatically stores the user data in sessions object. This allows us to access the user's information in subsequent middleware and procedures without having to re-validate the session.

We have already provided with a auth middleware which yo can find at server/middlewares/auth-middleware.ts which provides with basic authenticated access.

import type { Context, Next } from 'hono'
import { auth } from '@/lib/auth'
import { log } from '@/lib/logger'

export const authMiddleware = async (c: Context, next: Next) => {
try {
const session = await auth();

if (!session) {
return c.json({ error: 'Unauthorized' }, 401)
}

c.set('user', session.user) // Attach user data to context
await next()
} catch (err) {
console.error('Error in auth middleware:', err)
log("error", "Error in auth middleware: " + err)
return c.json({ error: 'Internal server error' }, 500)
}
}

Applying Middleware

To apply authentication to an endpoint, attach authMiddleware to the route definition:

app.get("/protected", authMiddleware, (c) => {
const user: any = c.get("user");
return c.json({ message: "Protected API Data", name: user.name });
});

Feature-based access

To implement feature-based access, such as role-based access control (RBAC), you can define a middleware that checks the user's role before allowing access to certain routes.

Here's an example of how you can create a role-based access middleware:

import type { Context, Next } from 'hono'

export const roleMiddleware = (requiredRole: string) => {
return async (c: Context, next: Next) => {
const user: any = c.get('user')

if (!user || user.role !== requiredRole) {
return c.json({ error: 'Forbidden' }, 403)
}

await next()
}
}

Applying Role-Based Middleware

To apply role-based access control to an endpoint, attach roleMiddleware with the required role to the route definition:

app.get("/admin", authMiddleware, roleMiddleware('admin'), (c) => {
return c.json({ message: "Admin API Data" });
});

In this example, only users with the role admin will be able to access the /admin route.