Skip to main content

Session Management

ISessionStore enables device-aware sessions — letting users see and revoke individual logged-in devices.


Session lifecycle


Interface

import { ISessionStore, SessionInfo } from '@nik2208/node-auth';

export class MySessionStore implements ISessionStore {
async createSession(info: Omit<SessionInfo, 'sessionHandle'>): Promise<SessionInfo> {
const sessionHandle = crypto.randomUUID();
await db('sessions').insert({ sessionHandle, ...info });
return { sessionHandle, ...info };
}

async getSession(sessionHandle: string): Promise<SessionInfo | null> {
return db('sessions').where({ sessionHandle }).first() ?? null;
}

async getSessionsForUser(userId: string): Promise<SessionInfo[]> {
return db('sessions').where({ userId });
}

async updateSessionLastActive(sessionHandle: string): Promise<void> {
await db('sessions').where({ sessionHandle }).update({ lastActiveAt: new Date() });
}

async revokeSession(sessionHandle: string): Promise<void> {
await db('sessions').where({ sessionHandle }).delete();
}

async revokeAllSessionsForUser(userId: string): Promise<void> {
await db('sessions').where({ userId }).delete();
}

async deleteExpiredSessions(): Promise<void> {
await db('sessions').where('expiresAt', '<', new Date()).delete();
}
}

SessionInfo Model

interface SessionInfo {
sessionHandle: string; // Unique opaque identifier
userId: string;
tenantId?: string;
createdAt: Date;
expiresAt: Date;
lastActiveAt?: Date;
userAgent?: string;
ipAddress?: string;
data?: Record<string, unknown>;
}

Usage

app.use('/auth', auth.router({ sessionStore }));

Sessions are automatically created on login and updated on each token refresh. Expired sessions can be purged via:

POST /auth/sessions/cleanup

This endpoint is only mounted when sessionStore is provided and its deleteExpiredSessions method is implemented.

Managing sessions via Admin Panel

The Admin Panel's Sessions tab shows all active sessions and lets you revoke individual ones:

app.use('/admin', createAdminRouter(userStore, {
adminSecret: process.env.ADMIN_SECRET!,
sessionStore,
}));

Or via the Admin REST API directly:

// List all sessions
const sessions = await fetch('/admin/api/sessions', {
headers: { Authorization: `Bearer ${adminSecret}` },
}).then(r => r.json());

// Revoke one session
await fetch(`/admin/api/sessions/${sessionHandle}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${adminSecret}` },
});