Sessions
WebJs provides a Session class with a SessionStorage interface, inspired by Remix. Storage owns the session lifecycle: storage.read(cookie) → Session, storage.save(session) → cookie. Two built-in storage implementations cover most use cases.
Setup
Add session middleware in middleware.ts:
// middleware.ts
import { session, cookieSessionStorage } from '@webjsdev/server';
export default session({
secret: process.env.SESSION_SECRET,
storage: cookieSessionStorage(), // or storeSessionStorage() for Redis
});
The only requirement is SESSION_SECRET (or pass secret directly), the key used to sign session cookies.
SessionStorage Implementations
cookieSessionStorage() (default)
All session data lives in the cookie itself. Stateless, with no server-side storage needed.
- Scales horizontally with no shared storage.
- 4 KB cookie size limit applies (after signing overhead).
- Every response includes the full session cookie.
import { session, cookieSessionStorage } from '@webjsdev/server';
export default session({
secret: process.env.SESSION_SECRET,
storage: cookieSessionStorage(),
});
storeSessionStorage() (production)
Only a session ID is stored in the cookie. Session data lives in the global cache store, which is in-memory by default. Switch to Redis for horizontal scaling by calling setStore(redisStore({ url: process.env.REDIS_URL })) once at app startup.
- No payload size limit beyond store key size.
- Server-side invalidation: delete the store entry and the session is gone.
- For production, use with Redis:
setStore(redisStore(...)).
import { session, storeSessionStorage } from '@webjsdev/server';
export default session({
secret: process.env.SESSION_SECRET,
storage: storeSessionStorage(), // uses getStore(), memory or Redis
});
Session Class API
Use getSession(req) in any server-side code (API routes, server actions, middleware):
import { getSession } from '@webjsdev/server';
const s = getSession(req);
s.get(key)
Returns the value for the key, checking both regular data and flash data.
const userId = s.get('userId');
s.set(key, value)
Sets a value. Pass null or undefined to delete the key.
s.set('userId', user.id);
s.set('role', 'admin');
s.has(key)
Returns true if the key exists in either regular or flash data.
if (s.has('userId')) { /* authenticated */ }
s.flash(key, value)
Sets a value that exists for one request only. Use for success/error messages after redirects.
s.flash('message', 'Post created!');
// Next request: s.get('message') → 'Post created!'
// Request after: s.get('message') → undefined
s.destroy()
Clears all session data and removes the cookie. Use for logout flows.
s.destroy();
s.regenerateId(deleteOld?)
Regenerates the session ID. Call after login to prevent session fixation attacks. Pass true to delete the old session entry from the store.
// After successful login:
s.set('userId', user.id);
s.regenerateId(true); // new ID, old store entry deleted
Example: Login Flow
// app/api/login/route.ts
import { getSession } from '@webjsdev/server';
import { db } from '#db/connection.server.ts';
import { verifyPassword } from '#lib/auth.server.ts';
export async function POST(req: Request) {
const { email, password } = await req.json();
const user = await db.query.users.findFirst({ where: { email } });
if (!user || !await verifyPassword(password, user.passwordHash)) {
return Response.json({ error: 'Invalid credentials' }, { status: 401 });
}
const s = getSession(req);
s.set('userId', user.id);
s.set('role', user.role);
s.regenerateId(true);
return Response.json({ ok: true });
}
Example: Logout
// app/api/logout/route.ts
import { getSession } from '@webjsdev/server';
export async function POST(req: Request) {
const s = getSession(req);
s.destroy();
return Response.json({ ok: true });
}
Example: Flash Messages
// In a server action after creating a post:
const s = getSession(req);
s.flash('success', 'Post published!');
// In the page that renders after redirect:
const s = getSession(req);
const message = s.get('success'); // 'Post published!', only this request
Session Options
The session() middleware accepts these options:
session({
secret: '...', // required (or SESSION_SECRET env var)
storage: cookieSessionStorage(), // default: cookieSessionStorage()
cookieName: 'webjs.sid', // default: 'webjs.sid'
maxAge: 86400_000, // 24 hours in ms (default)
path: '/', // cookie path (default: '/')
httpOnly: true, // default: true
secure: true, // default: true
sameSite: 'Lax', // default: 'Lax'
})
Next Steps
- Caching: the cache store that backs server-side sessions
- Authentication: NextAuth-style auth built on top of sessions
- Middleware: run session checks before route handlers