@davaux/session
Provides secure, signed cookie sessions backed by HMAC-SHA256. Session data is stored entirely in a cookie — no server-side session store required. The payload is JSON-encoded and signed with your secret key; tampering with the cookie invalidates it automatically.
Installation
npm install @davaux/session
Basic setup
Register the middleware in src/middleware.ts:
// src/middleware.ts
import { defineMiddleware } from 'davaux'
import { sessionMiddleware } from '@davaux/session'
const session = sessionMiddleware({
secret: process.env.SESSION_SECRET!,
})
export default defineMiddleware((ctx, next) => session(ctx, next))
Options
| Option | Type | Default | Description |
|---|---|---|---|
secret | string | string[] | required | HMAC signing key(s). Use an array for key rotation. |
cookieName | string | 'session' | Name of the cookie to read/write. |
httpOnly | boolean | true | Sets the HttpOnly flag on the session cookie. |
secure | boolean | true in production | Sets the Secure flag. |
sameSite | 'strict' | 'lax' | 'none' | 'lax' | SameSite cookie attribute. |
maxAge | number | 604800 (7 days) | Cookie lifetime in seconds. |
path | string | '/' | Cookie path scope. |
Using the session
After the middleware runs, ctx.state.session is available in all downstream handlers, pages, and layouts:
// src/routes/login.page.tsx (action)
import { defineAction, redirect } from 'davaux'
export const action = defineAction(async (ctx) => {
const data = await ctx.form()
const user = await verifyCredentials(
data.get('email') as string,
data.get('password') as string,
)
if (!user) {
return { error: 'Invalid credentials' }
}
ctx.state.session.set('userId', user.id)
ctx.state.session.set('role', user.role)
redirect('/dashboard')
})
// src/routes/dashboard/_middleware.ts
import { defineMiddleware, redirect } from 'davaux'
export default defineMiddleware(async (ctx, next) => {
const userId = ctx.state.session.get('userId')
if (!userId) {
redirect('/login')
}
const user = await db.users.findById(userId)
ctx.state.user = user
return next()
})
Session API
| Method | Description |
|---|---|
session.get(key) | Returns the value for key, or undefined |
session.set(key, value) | Stores value under key |
session.delete(key) | Removes a specific key from the session |
session.destroy() | Clears all session data and expires the cookie |
Key rotation
Pass an array of secrets to support graceful rotation. The first key is used for signing new sessions; all keys are tried when verifying existing ones:
sessionMiddleware({
secret: [
process.env.SESSION_SECRET_NEW!, // used to sign
process.env.SESSION_SECRET_OLD!, // used to verify legacy sessions
],
})
Once all active user sessions have been re-issued with the new key, remove the old key from the array.
TypeScript: augmenting State
Add type information for the session to your project's type declarations:
// src/types.d.ts
import '@davaux/session'
declare module 'davaux' {
interface State {
session: import('@davaux/session').Session
}
}
This gives you full autocomplete on ctx.state.session throughout the codebase.
Flash messages
Flash messages are one-time values that survive a single redirect — useful for showing success or error notices after a form submission.
Writing a flash message (before redirecting):
// src/routes/settings.page.tsx
import { defineAction, redirect } from 'davaux'
export const action = defineAction(async (ctx) => {
await saveSettings(await ctx.form())
ctx.flash('success', 'Settings saved!')
redirect('/settings')
})
Reading and consuming a flash message (on the destination page):
// src/routes/settings.page.tsx
import { definePage } from 'davaux'
export default definePage((ctx) => {
const message = ctx.flash('success') // string | undefined; consumed after this read
return (
<main>
{message && <p class="notice">{message}</p>}
<h1>Settings</h1>
</main>
)
})
Flash messages are stored in the session under a reserved namespace and automatically removed after being read. ctx.flash() requires @davaux/session to be registered — calling it without the session middleware will throw.
Cookie size limit
Browser cookies are limited to 4096 bytes. Since session data is stored in the cookie (after JSON encoding + base64 + HMAC signature), keep your session payload small. Store only identifiers (user ID, role, CSRF token) and look up the rest on each request from a database or cache.
If you need large session payloads, consider a Redis-backed session store.