Hono Sessions Middleware
hono-sessions is a middleware library designed for the Hono web framework, providing robust cookie-based session management. Currently at version 0.8.1, the library is actively maintained with a focus on stability and features like `autoExtendExpiration` and improved type safety. It differentiates itself by supporting a wide array of runtimes, including Node.js (v20+), Deno, Bun, Cloudflare Workers, and Cloudflare Pages, leveraging the Web Crypto API for secure, encrypted cookies via `iron-webcrypto`. Key features include support for 'flash messages' (data deleted after one read), built-in Memory and Cookie storage drivers, extensible architecture for custom drivers (like Bun SQLite), and strong TypeScript typing for session variables. It offers a flexible approach to user session management, particularly powerful in serverless and edge environments where persistent server-side state might be impractical.
Common errors
-
TypeError: sessionMiddleware is not a function
cause Attempting to use CommonJS `require` syntax or incorrect named import for an ESM-only package.fixEnsure you are using ESM `import { sessionMiddleware } from 'hono-sessions'` and that your environment supports ESM. -
Error: encryptionKey is required.
cause The `encryptionKey` was not provided in the `sessionMiddleware` options when using `CookieStore`.fixAdd a `encryptionKey` string (at least 32 characters long) to the `sessionMiddleware` configuration. -
ReferenceError: crypto is not defined (or similar Web Crypto API error)
cause The runtime environment does not support the Web Crypto API, or the Node.js version is too old (<v20).fixUpgrade your Node.js version to 20 or higher, or ensure you are running in an environment with Web Crypto API support (e.g., Deno, Bun, Cloudflare Workers). -
TypeError: c.get is not a function
cause This typically indicates that the Hono `c` context does not have the `session` variable, likely due to the `sessionMiddleware` not being applied or a mismatch in Hono versions preventing context augmentation.fixVerify that `app.use('*', sessionMiddleware(...))` is correctly placed before any routes accessing `c.get('session')`. Also, ensure your 'hono' peer dependency is `^4.0.0` or newer.
Warnings
- breaking Hono v4.0.0 or higher is required as a peer dependency. Ensure your 'hono' package meets this requirement to prevent type mismatches and runtime errors.
- gotcha The `encryptionKey` option is mandatory when using `CookieStore` and highly recommended for other storage drivers to ensure session data integrity and confidentiality. It must be at least 32 characters long.
- gotcha The Web Crypto API is a required runtime dependency for `hono-sessions` due to its use of `iron-webcrypto` for encryption. Ensure your chosen runtime environment (e.g., Node.js v20+, Deno, Bun, Cloudflare Workers) supports this API.
- gotcha The `cookieOptions.path` property must be set to `'/'` for `hono-sessions` to function correctly across all routes. If omitted or set incorrectly, sessions might not persist as expected.
- gotcha The `session_key_rotation` feature is explicitly stated to have no effect when using the `CookieStore` because cookie-only sessions lack server-side state that would benefit from key rotation.
Install
-
npm install hono-sessions -
yarn add hono-sessions -
pnpm add hono-sessions
Imports
- sessionMiddleware
const { sessionMiddleware } = require('hono-sessions')import { sessionMiddleware } from 'hono-sessions' - CookieStore
import CookieStore from 'hono-sessions/CookieStore'
import { CookieStore } from 'hono-sessions' - Session
import { Session } from 'hono-sessions'
Quickstart
import { Hono } from 'hono'
import {
Session,
sessionMiddleware,
CookieStore
} from 'hono-sessions'
// Add types to your session data for improved safety and autocomplete
type SessionDataTypes = {
'counter': number,
'flashMessage'?: string
}
// Set up your Hono instance with session types
const app = new Hono<{
Variables: {
session: Session<SessionDataTypes>,
session_key_rotation: boolean // Type for internal middleware variable
}
}>()
const store = new CookieStore()
app.use('*', sessionMiddleware({
store,
// IMPORTANT: encryptionKey must be at least 32 characters long for CookieStore
encryptionKey: process.env.SESSION_ENCRYPTION_KEY ?? 'super-secret-key-that-is-at-least-thirty-two-characters-long',
expireAfterSeconds: 900, // Session expires after 15 minutes of inactivity
autoExtendExpiration: true, // Automatically extends session on activity (default: true)
cookieOptions: {
sameSite: 'Lax', // Recommended for basic CSRF protection
path: '/', // Required for the library to function correctly
httpOnly: true, // Recommended to prevent client-side script access
secure: process.env.NODE_ENV === 'production' // Use 'Secure' in production
},
}))
app.get('/', async (c) => {
const session = c.get('session')
const currentCounter = session.get('counter') || 0;
session.set('counter', currentCounter + 1);
const flash = session.getFlash('flashMessage');
if (flash) {
console.log(`Flash message: ${flash}`);
}
return c.html(`
<h1>You have visited this page ${session.get('counter')} times</h1>
${flash ? `<p style="color: green;">${flash}</p>` : ''}
<p><a href="/set-flash">Set a flash message</a></p>
<p><a href="/read">Read counter (and touch session)</a></p>
`)
})
app.get('/set-flash', async (c) => {
const session = c.get('session');
session.setFlash('flashMessage', 'This is a one-time message!');
return c.redirect('/');
});
app.get('/read', (c) => {
const session = c.get('session')
session.touch() // Explicitly update the session expiration time
return c.json({
counter: session.get('counter'),
flash: session.getFlash('flashMessage') // This will be undefined after first read
})
})
// For Bun, Cloudflare Workers, etc.
// export default {
// port: 3000,
// fetch: app.fetch
// }
// For Deno
// Deno.serve(app.fetch)
// For Node.js (via Hono adapter)
// import { serve } from '@hono/node-server';
// serve({ fetch: app.fetch, port: 3000 });