# connect-mongo connect-mongo is a MongoDB session store for Express and Connect applications, written in TypeScript. It provides persistent session storage using MongoDB, allowing user sessions to survive server restarts and enabling session sharing across multiple application instances in clustered environments. The library supports multiple connection methods (connection strings, existing MongoClient instances, or Promises), automatic session expiration via MongoDB TTL indexes or interval-based cleanup, lazy session updates to reduce database writes, and transparent encryption/decryption of session data using either the Web Crypto API (AES-GCM) or the legacy kruptein library. It is compatible with Express up to 5.0, MongoDB Node.js driver 5.x-7.x, and MongoDB server versions 4.4-8.0. ## MongoStore.create - Create Session Store with Connection String Creates a new MongoStore instance using a MongoDB connection string. This is the simplest and recommended method for establishing a new database connection for session storage. ```javascript const express = require('express') const session = require('express-session') const MongoStore = require('connect-mongo') const app = express() // Basic usage with connection string app.use(session({ secret: 'your-session-secret', resave: false, saveUninitialized: false, store: MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp' }) })) // Advanced usage with authentication and options app.use(session({ secret: 'your-session-secret', resave: false, saveUninitialized: false, store: MongoStore.create({ mongoUrl: 'mongodb://user:password@localhost:27017/myapp?authSource=admin', dbName: 'sessions-db', // Override database name collectionName: 'user_sessions', // Custom collection name (default: 'sessions') ttl: 14 * 24 * 60 * 60, // Session TTL in seconds (default: 14 days) mongoOptions: { // Additional MongoClient options (TLS, connection pool, etc.) maxPoolSize: 10 } }) })) app.get('/', (req, res) => { req.session.userId = 'user-123' res.send('Session stored!') }) app.listen(3000) ``` ## MongoStore.create - Reuse Existing MongoClient Creates a MongoStore instance by reusing an existing MongoClient connection or Promise. This is useful when your application already has a database connection that you want to share with session storage. ```javascript const express = require('express') const session = require('express-session') const MongoStore = require('connect-mongo') const { MongoClient } = require('mongodb') const app = express() // Option 1: Using an existing MongoClient instance const client = new MongoClient('mongodb://localhost:27017') async function initApp() { await client.connect() app.use(session({ secret: 'your-session-secret', resave: false, saveUninitialized: false, store: MongoStore.create({ client: client, dbName: 'myapp' }) })) app.listen(3000) } // Option 2: Using a client Promise const clientPromise = MongoClient.connect('mongodb://localhost:27017') app.use(session({ secret: 'your-session-secret', resave: false, saveUninitialized: false, store: MongoStore.create({ clientPromise: clientPromise, dbName: 'myapp' }) })) initApp() ``` ## MongoStore with Mongoose Integration Reuses an existing Mongoose connection for session storage, avoiding the need to maintain separate database connections for your application data and sessions. ```javascript const express = require('express') const session = require('express-session') const MongoStore = require('connect-mongo') const mongoose = require('mongoose') const app = express() const mongoUrl = 'mongodb://localhost:27017' const dbName = 'myapp' // Connect mongoose and extract the underlying MongoClient const clientPromise = mongoose.connect(mongoUrl, { dbName }) .then((connection) => connection.connection.getClient()) app.use(session({ secret: 'your-session-secret', resave: false, saveUninitialized: false, store: MongoStore.create({ clientPromise: clientPromise, dbName: dbName, stringify: false, // Store as native BSON objects instead of JSON strings autoRemove: 'interval', // Use interval-based cleanup instead of TTL index autoRemoveInterval: 10 // Clean up every 10 minutes }) })) app.get('/', (req, res) => { req.session.foo = 'test-value' res.send('Hello World!') }) app.listen(3000, () => { console.log('App listening on port 3000') }) ``` ## Session Expiration and Auto-Remove Modes Configures automatic cleanup of expired sessions using MongoDB's TTL index (native), interval-based deletion, or manual management. ```javascript const MongoStore = require('connect-mongo') // Mode 1: Native TTL index (default) - MongoDB automatically removes expired sessions const storeNative = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', autoRemove: 'native', // Creates TTL index on 'expires' field ttl: 14 * 24 * 60 * 60 // 14 days in seconds }) // Mode 2: Interval-based cleanup - For environments without TTL support (e.g., Azure Cosmos DB) const storeInterval = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', autoRemove: 'interval', autoRemoveInterval: 10 // Run cleanup every 10 minutes }) // Mode 3: Disabled - Manage TTL index manually in production const storeDisabled = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', autoRemove: 'disabled' }) // Custom session expiration from cookie app.use(session({ secret: 'secret', cookie: { maxAge: 1000 * 60 * 60 * 24 * 7 // 7 days - overrides store TTL }, store: storeNative })) ``` ## Lazy Session Update with touchAfter Reduces database writes by only updating sessions after a specified time period, improving performance for high-traffic applications. ```javascript const express = require('express') const session = require('express-session') const MongoStore = require('connect-mongo') const app = express() app.use(session({ secret: 'keyboard cat', saveUninitialized: false, // Don't create session until data is stored resave: false, // Don't save unmodified sessions store: MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', touchAfter: 24 * 3600 // Only update session once per 24 hours }) })) // Session will only be written to DB when: // 1. Session data actually changes, OR // 2. More than 24 hours have passed since last update app.get('/page', (req, res) => { // This won't trigger a DB write if session is unchanged and < 24 hours old req.session.views = (req.session.views || 0) + 1 res.send(`Page views: ${req.session.views}`) }) app.listen(3000) ``` ## Transparent Encryption with Web Crypto API Encrypts session data at rest using AES-GCM encryption via the Web Crypto API. This is the recommended approach for protecting sensitive session data. ```typescript import express from 'express' import session from 'express-session' import MongoStore, { createWebCryptoAdapter } from 'connect-mongo' const app = express() // Using Web Crypto API (recommended for new projects) const store = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', cryptoAdapter: createWebCryptoAdapter({ secret: process.env.SESSION_SECRET!, // Your encryption key algorithm: 'AES-GCM', // Default, most secure option encoding: 'base64', // Output encoding: 'base64' | 'base64url' | 'hex' iterations: 310000 // PBKDF2 iterations for key derivation }) }) app.use(session({ secret: 'cookie-signing-secret', resave: false, saveUninitialized: false, store })) // Session data is automatically encrypted before storage // and decrypted when retrieved app.get('/', (req, res) => { req.session.sensitiveData = 'encrypted-value' res.send('Session encrypted!') }) app.listen(3000) ``` ## Legacy Encryption with Kruptein Adapter Provides backward-compatible encryption using the kruptein library for existing applications or when specific cipher algorithms are required. ```javascript const MongoStore = require('connect-mongo') const { createKrupteinAdapter } = require('connect-mongo') // Option 1: Using the legacy crypto option (auto-wrapped to kruptein adapter) const storeLegacy = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', crypto: { secret: 'your-32-char-secret-key-here!!!', algorithm: 'aes-256-gcm', // Default hashing: 'sha512', // Key derivation hash encodeas: 'hex', // Output encoding key_size: 32, // AES block size iv_size: 16, // Initialization vector size at_size: 16 // Authentication tag size } }) // Option 2: Explicitly creating the kruptein adapter const storeExplicit = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', cryptoAdapter: createKrupteinAdapter({ secret: 'your-secret-key' }) }) // Note: Cannot use both crypto and cryptoAdapter - will throw error ``` ## Store Events MongoStore emits events for session lifecycle operations, useful for logging, debugging, or triggering side effects. ```javascript const express = require('express') const session = require('express-session') const MongoStore = require('connect-mongo') const app = express() const store = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp' }) // Listen for session events store.on('create', (sessionId) => { console.log(`Session created: ${sessionId}`) }) store.on('update', (sessionId) => { console.log(`Session updated: ${sessionId}`) }) store.on('touch', (sessionId) => { console.log(`Session touched (expiry refreshed): ${sessionId}`) }) store.on('set', (sessionId) => { console.log(`Session set (created or updated): ${sessionId}`) }) store.on('destroy', (sessionId) => { console.log(`Session destroyed: ${sessionId}`) }) app.use(session({ secret: 'secret', store: store })) app.get('/logout', (req, res) => { req.session.destroy((err) => { if (err) return res.status(500).send('Logout failed') res.send('Logged out') // Will trigger 'destroy' event }) }) app.listen(3000) ``` ## Custom Serialization and Session ID Transformation Provides hooks for customizing how sessions are serialized to MongoDB and how session IDs are transformed for storage. ```javascript const MongoStore = require('connect-mongo') const crypto = require('crypto') const store = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', // Store sessions as native BSON objects instead of JSON strings stringify: false, // Custom serialization: add metadata before storage serialize: (session) => { return { ...session, _metadata: { serializedAt: new Date(), version: '1.0' } } }, // Custom unserialization: process session after retrieval unserialize: (payload) => { const { _metadata, ...session } = payload return session }, // Transform session IDs (e.g., for hashing or prefixing) transformId: (sessionId) => { // Hash session IDs for additional security return crypto.createHash('sha256').update(sessionId).digest('hex') } }) ``` ## Session Timestamps Enables automatic tracking of session creation and update times for auditing purposes. ```javascript const MongoStore = require('connect-mongo') const store = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', timestamps: true // Adds createdAt and updatedAt fields to session documents }) // Session document structure in MongoDB: // { // _id: "session-id", // session: { ... }, // expires: ISODate("2024-01-15T00:00:00Z"), // createdAt: ISODate("2024-01-01T00:00:00Z"), // Set on first insert // updatedAt: ISODate("2024-01-08T12:30:00Z") // Updated on every write/touch // } ``` ## TypeScript Usage with Session Type Extension Provides full TypeScript support with type-safe session data through declaration merging. ```typescript import express, { Request, Response } from 'express' import session from 'express-session' import MongoStore from 'connect-mongo' // Extend session data interface with custom properties declare module 'express-session' { interface SessionData { userId: string isAuthenticated: boolean preferences: { theme: 'light' | 'dark' language: string } } } const app = express() const store = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp', stringify: false }) app.use(session({ secret: 'your-session-secret', resave: false, saveUninitialized: false, store })) app.post('/login', (req: Request, res: Response) => { // TypeScript knows these properties exist req.session.userId = 'user-123' req.session.isAuthenticated = true req.session.preferences = { theme: 'dark', language: 'en' } res.send('Logged in!') }) app.get('/profile', (req: Request, res: Response) => { if (!req.session.isAuthenticated) { return res.status(401).send('Not authenticated') } res.json({ userId: req.session.userId, preferences: req.session.preferences }) }) app.listen(3000, () => { console.log('TypeScript app listening on port 3000') }) ``` ## Store Management Methods Provides methods for managing sessions programmatically, including getting all sessions, counting sessions, clearing all sessions, and closing the database connection. ```javascript const MongoStore = require('connect-mongo') const store = MongoStore.create({ mongoUrl: 'mongodb://localhost:27017/myapp' }) // Get all active sessions store.all((err, sessions) => { if (err) return console.error('Error fetching sessions:', err) console.log('Active sessions:', sessions) // Returns: [{ cookie: {...}, userId: '...' }, ...] }) // Get session count store.length((err, count) => { if (err) return console.error('Error counting sessions:', err) console.log('Total sessions:', count) }) // Get a specific session by ID store.get('session-id-here', (err, session) => { if (err) return console.error('Error fetching session:', err) console.log('Session data:', session) }) // Delete a specific session store.destroy('session-id-here', (err) => { if (err) return console.error('Error destroying session:', err) console.log('Session destroyed') }) // Clear all sessions (use with caution!) store.clear((err) => { if (err) return console.error('Error clearing sessions:', err) console.log('All sessions cleared') }) // Close database connection on shutdown process.on('SIGTERM', async () => { await store.close() console.log('Store connection closed') process.exit(0) }) ``` ## Summary connect-mongo is primarily used for persistent session storage in Express/Connect applications that require sessions to survive server restarts, scale across multiple instances in load-balanced environments, or share sessions between different services. Common use cases include authentication systems where user login state must persist, shopping cart applications that need to maintain cart contents across visits, and multi-server deployments where session affinity is not guaranteed. Integration typically follows one of three patterns: creating a new connection via `mongoUrl` for standalone applications, reusing an existing MongoClient or Promise for applications that already manage their own database connections, or extracting the underlying client from Mongoose for applications using that ODM. For production deployments, consider enabling encryption with `createWebCryptoAdapter`, using `touchAfter` to reduce database writes, setting appropriate TTL values, and choosing the correct `autoRemove` mode based on your MongoDB provider's capabilities.