Last Updated: 3/11/2026
Built-in Middleware
Hono includes powerful middleware for common tasks like authentication, CORS, logging, and security.
Authentication
Basic Auth
HTTP Basic Authentication:
import { basicAuth } from 'hono/basic-auth'
app.use(
'/admin/*',
basicAuth({
username: 'admin',
password: 'secret',
})
)
app.get('/admin', (c) => c.text('Admin panel'))With environment variables:
app.use('/admin/*', async (c, next) => {
const auth = basicAuth({
username: c.env.USERNAME,
password: c.env.PASSWORD,
})
return auth(c, next)
})Bearer Auth
Token-based authentication:
import { bearerAuth } from 'hono/bearer-auth'
app.use(
'/api/*',
bearerAuth({
token: 'your-secret-token',
})
)With custom verification:
app.use(
'/api/*',
bearerAuth({
verifyToken: async (token, c) => {
return token === await c.env.DB.getToken()
},
})
)JWT Auth
JSON Web Token authentication:
import { jwt } from 'hono/jwt'
app.use(
'/protected/*',
jwt({
secret: 'your-secret-key',
})
)
app.get('/protected/data', (c) => {
const payload = c.get('jwtPayload')
return c.json({ user: payload })
})With algorithm:
app.use(
'/protected/*',
jwt({
secret: 'your-secret-key',
alg: 'HS256',
})
)CORS
Handle Cross-Origin Resource Sharing:
import { cors } from 'hono/cors'
// Default (allow all origins)
app.use('/api/*', cors())
// With options
app.use(
'/api/*',
cors({
origin: 'https://example.com',
allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
allowHeaders: ['Content-Type', 'Authorization'],
exposeHeaders: ['X-Total-Count'],
credentials: true,
maxAge: 600,
})
)
// Multiple origins
app.use(
'/api/*',
cors({
origin: ['https://example.com', 'https://app.example.com'],
})
)
// Dynamic origin
app.use(
'/api/*',
cors({
origin: (origin) => {
return origin.endsWith('.example.com') ? origin : 'https://example.com'
},
})
)Logger
Log requests:
import { logger } from 'hono/logger'
app.use(logger())
// Custom format
app.use(
logger((str, ...rest) => {
console.log(`[Custom] ${str}`, ...rest)
})
)Security
Secure Headers
Add security headers:
import { secureHeaders } from 'hono/secure-headers'
app.use(secureHeaders())
// Custom options
app.use(
secureHeaders({
contentSecurityPolicy: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
},
xFrameOptions: 'DENY',
xContentTypeOptions: 'nosniff',
})
)CSRF Protection
Prevent Cross-Site Request Forgery:
import { csrf } from 'hono/csrf'
app.use(csrf())
// With options
app.use(
csrf({
origin: 'https://example.com',
})
)Caching
ETag
Add ETag headers:
import { etag } from 'hono/etag'
app.use(etag())
// With options
app.use(
etag({
weak: true,
})
)Cache
Cache responses:
import { cache } from 'hono/cache'
app.use(
'*',
cache({
cacheName: 'my-app',
cacheControl: 'max-age=3600',
})
)Compression
Compress responses:
import { compress } from 'hono/compress'
app.use(compress())
// With options
app.use(
compress({
encoding: 'gzip',
})
)Body Limit
Limit request body size:
import { bodyLimit } from 'hono/body-limit'
app.use(
'/upload',
bodyLimit({
maxSize: 1024 * 1024, // 1MB
onError: (c) => {
return c.text('Payload too large', 413)
},
})
)Pretty JSON
Format JSON responses:
import { prettyJSON } from 'hono/pretty-json'
app.use(prettyJSON())
// Only in development
if (process.env.NODE_ENV === 'development') {
app.use(prettyJSON())
}Request ID
Add unique request IDs:
import { requestId } from 'hono/request-id'
app.use(requestId())
app.get('/', (c) => {
const id = c.get('requestId')
return c.json({ requestId: id })
})
// Custom generator
app.use(
requestId({
generator: () => crypto.randomUUID(),
})
)Timeout
Timeout long-running requests:
import { timeout } from 'hono/timeout'
app.use(
'/api/*',
timeout(5000) // 5 seconds
)
// With custom handler
app.use(
'/api/*',
timeout(5000, (c) => {
return c.json({ error: 'Request timeout' }, 504)
})
)Timing
Add Server-Timing headers:
import { timing } from 'hono/timing'
app.use(timing())
app.get('/data', async (c) => {
const start = Date.now()
const data = await fetchData()
c.res.headers.append('Server-Timing', `db;dur=${Date.now() - start}`)
return c.json(data)
})Method Override
Override HTTP methods:
import { methodOverride } from 'hono/method-override'
app.use(methodOverride())
// Now POST with _method=DELETE works as DELETETrailing Slash
Handle trailing slashes:
import { trimTrailingSlash } from 'hono/trailing-slash'
app.use(trimTrailingSlash())
// /path/ redirects to /pathIP Restriction
Restrict access by IP:
import { ipRestriction } from 'hono/ip-restriction'
app.use(
'/admin/*',
ipRestriction(getConnInfo, {
allowList: ['192.168.1.1', '10.0.0.0/8'],
})
)JSX Renderer
Render JSX with layouts:
import { jsxRenderer } from 'hono/jsx-renderer'
app.use(
'*',
jsxRenderer(({ children }) => {
return (
<html>
<body>
<header>My Site</header>
{children}
<footer>© 2024</footer>
</body>
</html>
)
})
)
app.get('/', (c) => {
return c.render(<h1>Hello!</h1>)
})Combine
Combine multiple middleware:
import { combine } from 'hono/combine'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
const middleware = combine(logger(), cors())
app.use('/api/*', middleware)Next Steps
You’ve completed the critical path! Explore more topics: