
Security News
Crates.io Users Targeted by Phishing Emails
The Rust Security Response WG is warning of phishing emails from rustfoundation.dev targeting crates.io users.
@analog-tools/session
Advanced tools
✨ Simplified Session Management ✨
Completely redesigned with a clean, functional API. No more over-engineered abstractions!
A simple, performant session management library for H3-based applications (Nuxt, Nitro, AnalogJS). Designed for simplicity and efficiency with a single API pattern.
This version introduces a complete API redesign that simplifies the previous over-engineered approach:
Session
class and SessionHandler
interfaceUnstorageSessionStore
wrapper and registerStorage
factoryMigration Guide: See Migration from v0.0.5 section below.
npm install @analog-tools/session
import { defineEventHandler } from 'h3';
import { useSession, getSession, updateSession, createMemoryStore } from '@analog-tools/session';
const store = createMemoryStore();
export default defineEventHandler(async (event) => {
// Initialize session middleware
await useSession(event, {
store,
secret: 'your-secret-key',
maxAge: 86400, // 24 hours
});
// Get current session data
const session = getSession(event);
console.log('Current session:', session);
// Update session data
await updateSession(event, (data) => ({
visits: (data.visits || 0) + 1,
lastAccess: Date.now(),
}));
return {
visits: getSession(event)?.visits || 0,
};
});
import { createRedisStore } from '@analog-tools/session';
const store = createRedisStore({
host: 'localhost',
port: 6379,
// Optional: password, db, etc.
});
export default defineEventHandler(async (event) => {
await useSession(event, {
store,
secret: ['new-secret', 'old-secret'], // Supports rotation
name: 'my-app-session',
maxAge: 3600,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'strict',
},
});
// Your session logic here
});
useSession(event, config)
Initialize session middleware for an H3 event. Must be called before other session operations.
await useSession(event, {
store: Storage<T>, // Direct unstorage Storage instance
secret: string | string[], // Secret(s) for signing cookies
name?: string, // Cookie name (default: 'connect.sid')
maxAge?: number, // TTL in seconds (default: 86400)
cookie?: CookieOptions, // Standard cookie options
generate?: () => T, // Optional initial data generator
});
getSession<T>(event): T | null
Get current session data from the event context.
const session = getSession<{ userId?: string }>(event);
if (session?.userId) {
console.log('User ID:', session.userId);
}
updateSession<T>(event, updater)
Update session data immutably and persist to storage.
await updateSession(event, (currentData) => ({
lastLogin: new Date().toISOString(),
loginCount: (currentData.loginCount || 0) + 1,
}));
destroySession(event)
Destroy the current session, clear storage and cookies.
await destroySession(event);
regenerateSession<T>(event)
Regenerate session ID while preserving data (useful after login).
await regenerateSession(event);
createMemoryStore<T>(options?)
Create in-memory storage for development and testing.
const store = createMemoryStore();
createRedisStore<T>(options)
Create Redis-backed storage for production.
const store = createRedisStore({
url: 'redis://localhost:6379',
// or individual options:
host: 'localhost',
port: 6379,
password: 'optional',
db: 0,
});
signCookie(value, secret): Promise<string>
Sign a cookie value with HMAC-SHA256.
unsignCookie(signedValue, secrets): Promise<string | null>
Verify and unsign a cookie value, supports multiple secrets for rotation.
import { defineEventHandler, readBody, createError } from 'h3';
import {
useSession,
getSession,
updateSession,
destroySession,
regenerateSession,
createRedisStore
} from '@analog-tools/session';
// Session configuration (define once, reuse across routes)
const sessionConfig = {
store: createRedisStore({ url: process.env.REDIS_URL }),
secret: process.env.SESSION_SECRET!,
maxAge: 3600, // 1 hour
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
sameSite: 'strict' as const,
},
};
// Login endpoint
export default defineEventHandler(async (event) => {
await useSession(event, sessionConfig);
const { username, password } = await readBody(event);
const user = await validateUser(username, password);
if (user) {
// Regenerate session ID for security
await regenerateSession(event);
// Store user data
await updateSession(event, () => ({
userId: user.id,
username: user.username,
loginTime: Date.now(),
}));
return { success: true };
}
return { success: false };
});
// Protected endpoint
export default defineEventHandler(async (event) => {
await useSession(event, sessionConfig);
const session = getSession(event);
if (!session?.userId) {
throw createError({
statusCode: 401,
statusMessage: 'Not authenticated',
});
}
return { user: session };
});
// Logout endpoint
export default defineEventHandler(async (event) => {
await useSession(event, sessionConfig);
await destroySession(event);
return { success: true };
});
interface UserSession {
userId?: string;
username?: string;
roles?: string[];
preferences?: Record<string, unknown>;
lastActivity?: number;
}
export default defineEventHandler(async (event) => {
await useSession<UserSession>(event, {
store: createRedisStore({ url: process.env.REDIS_URL }),
secret: process.env.SESSION_SECRET!,
generate: () => ({ lastActivity: Date.now() }),
});
const session = getSession<UserSession>(event);
// TypeScript knows session has UserSession shape
});
interface SessionConfig<T> {
store: Storage<T>; // Direct unstorage Storage
secret: string | string[]; // Support for key rotation
name?: string; // Cookie name (default: 'connect.sid')
maxAge?: number; // TTL in seconds (default: 86400)
cookie?: CookieOptions; // Cookie configuration
generate?: () => T; // Initial session data generator
}
interface CookieOptions {
domain?: string;
path?: string; // Default: '/'
secure?: boolean; // Default: false
httpOnly?: boolean; // Default: true
sameSite?: boolean | 'lax' | 'strict' | 'none'; // Default: 'lax'
}
If you're upgrading from v0.0.5 or earlier, here's how to migrate your code:
// If you were using the old Session class (not available in any released version)
// This is just for reference as the class was removed before public release
import { useSession, getSession, updateSession, createRedisStore } from '@analog-tools/session';
const store = createRedisStore({ host: 'localhost', port: 6379 });
export default defineEventHandler(async (event) => {
await useSession(event, { store, secret: 'key' });
await updateSession(event, (data) => ({
visits: (data.visits || 0) + 1
})); // Auto-saves
});
createRedisStore()
or createMemoryStore()
for storageuseSession(event, config)
getSession(event)
to get current session dataupdateSession(event, updater)
to modify session data (auto-saves)Contributions are welcome! Please read our Contributing Guide for details.
MIT © Gregor Speck
FAQs
Session management for AnalogJS server-side applications
We found that @analog-tools/session demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
The Rust Security Response WG is warning of phishing emails from rustfoundation.dev targeting crates.io users.
Product
Socket now lets you customize pull request alert headers, helping security teams share clear guidance right in PRs to speed reviews and reduce back-and-forth.
Product
Socket's Rust support is moving to Beta: all users can scan Cargo projects and generate SBOMs, including Cargo.toml-only crates, with Rust-aware supply chain checks.