Skip to main content

Overview

The MongoAuth class provides persistent authentication storage using MongoDB. It enables centralized session management with the benefits of document-based storage, complex querying capabilities, and robust data persistence for production-grade bot deployments.

Key Features

  • Document-Based Storage: Store sessions as MongoDB documents
  • Encrypted Storage: All session data encrypted with AES-256-GCM
  • Centralized Management: Single source of truth for all sessions
  • Query Capabilities: Leverage MongoDB’s powerful query engine
  • Audit Trails: Track session history and modifications
  • Scalability: Handle thousands of concurrent bot sessions
MongoAuth is ideal for production environments requiring centralized session management, audit capabilities, or existing MongoDB infrastructure.

Installation

MongoAuth requires the official MongoDB Node.js driver:
npm install mongodb

Constructor

new MongoAuth(uuid, collection)

Creates a new MongoAuth instance for managing bot authentication in MongoDB.
uuid
UUID
required
A valid UUID (v4) that uniquely identifies this bot instance. This UUID is used as the encryption key and stored with each document for session identification.
collection
Collection<IAuthState>
required
A MongoDB collection instance where authentication documents will be stored. The collection should be typed with the IAuthState interface for type safety.

Type Definition

interface IAuthState extends Document {
  uuid: UUID;
  key: string;      // MD5 hash of the data key
  encrypted: string; // Base64-encoded encrypted data
}

Example

import { Bot, MongoAuth } from "wapi";
import { MongoClient } from "mongodb";
import { randomUUID } from "node:crypto";

const client = await MongoClient.connect("mongodb://localhost:27017");
const db = client.db("wapi");
const collection = db.collection("sessions");

const uuid = randomUUID();
const auth = new MongoAuth(uuid, collection);

const bot = new Bot({ auth });

Throws

  • Error: If the provided UUID is not a valid UUID v4 format

Properties

uuid

uuid
UUID
The UUID associated with this authentication instance. This is the same UUID provided to the constructor.
const auth = new MongoAuth(uuid, collection);
console.log(auth.uuid); // "550e8400-e29b-41d4-a716-446655440000"

Methods

init()

Initializes the authentication system by loading or creating credentials and setting up the key store.
init(): Promise<IBotAuthInit>

Behavior

  1. Credential Loading: Queries MongoDB for existing credentials using the UUID
  2. New Session: If no credentials exist, generates new authentication credentials
  3. Key Store Setup: Initializes the Signal protocol key store for WhatsApp encryption
  4. Cache Population: Populates the in-memory cache with encrypted data

Returns

Example

import { MongoAuth } from "wapi";
import { MongoClient } from "mongodb";
import { randomUUID } from "node:crypto";

const client = await MongoClient.connect("mongodb://localhost:27017");
const db = client.db("wapi");
const collection = db.collection("sessions");

const auth = new MongoAuth(randomUUID(), collection);

// Initialize authentication
const { creds, keys } = await auth.init();

console.log("Credentials loaded:", !!creds);
console.log("Keys initialized:", !!keys);
This method is called automatically by the Bot class during initialization. You rarely need to call it directly.

save()

Persists the current authentication credentials to MongoDB.
save(): Promise<void>

Behavior

  1. Validation: Ensures credentials have been loaded via init()
  2. Serialization: Converts credentials to JSON format
  3. Encryption: Encrypts the data using AES-256-GCM
  4. Upsert: Updates existing document or inserts new one
  5. Cache Update: Updates the in-memory cache

MongoDB Operation

await collection.updateOne(
  { uuid: this.uuid, key: md5Hash },
  { $set: { encrypted: encryptedData } },
  { upsert: true }
);

Throws

  • Error: If credentials haven’t been initialized (“Credentials not loaded.”)

Example

import { MongoAuth } from "wapi";
import { MongoClient } from "mongodb";
import { randomUUID } from "node:crypto";

const client = await MongoClient.connect("mongodb://localhost:27017");
const db = client.db("wapi");
const collection = db.collection("sessions");

const auth = new MongoAuth(randomUUID(), collection);

// Initialize and save
await auth.init();
await auth.save();

console.log("Session saved to MongoDB");
The Bot class automatically saves credentials when authentication state changes. Manual calls to save() are typically unnecessary.

remove()

Deletes all authentication data from MongoDB and clears the cache.
remove(): Promise<void>

Behavior

  1. Batch Deletion: Deletes all documents matching the bot’s UUID
  2. Cache Clearing: Clears the in-memory cache

MongoDB Operation

await collection.deleteMany({ uuid: this.uuid });

Example

import { MongoAuth } from "wapi";
import { MongoClient } from "mongodb";
import { randomUUID } from "node:crypto";

const client = await MongoClient.connect("mongodb://localhost:27017");
const db = client.db("wapi");
const collection = db.collection("sessions");

const uuid = randomUUID();
const auth = new MongoAuth(uuid, collection);

// Remove session data
await auth.remove();
console.log("Session removed from MongoDB");
This operation is irreversible. After calling remove(), the bot will need to re-authenticate (scan QR code or enter OTP) on next startup.

Storage Details

Document Structure

Each session data point is stored as a separate document:
{
  _id: ObjectId("..."),
  uuid: "550e8400-e29b-41d4-a716-446655440000",
  key: "5f4dcc3b5aa765d61d8327deb882cf99",
  encrypted: "AES-encrypted-base64-string..."
}

Field Descriptions

_id
ObjectId
MongoDB’s unique document identifier, automatically generated.
uuid
UUID
The bot’s unique identifier. Used to query all documents belonging to a specific bot session.
key
string
MD5 hash of the original key name (e.g., “creds”, “pre-key-1”). Ensures consistent document identification.
encrypted
string
Base64-encoded AES-256-GCM encrypted data. Contains the actual session information.

Indexes

Create these indexes for optimal performance:
// Compound index for fast lookups
await collection.createIndex({ uuid: 1, key: 1 }, { unique: true });

// Index for bulk operations
await collection.createIndex({ uuid: 1 });

Encryption

  • Cipher: AES-256-GCM (Galois/Counter Mode)
  • Key: Derived from the bot’s UUID
  • Security: Authenticated encryption with associated data (AEAD)
  • Format: Encrypted data stored as base64 strings

Complete Examples

import { Bot, MongoAuth } from "wapi";
import { MongoClient } from "mongodb";
import { randomUUID } from "node:crypto";

const client = await MongoClient.connect(
  process.env.MONGODB_URI || "mongodb://localhost:27017"
);

const db = client.db("wapi");
const collection = db.collection("sessions");

const uuid = randomUUID();
const auth = new MongoAuth(uuid, collection);
const bot = new Bot({ auth });

bot.on("qr", (qr) => {
  console.log("Scan this QR code:", qr);
});

bot.on("open", (account) => {
  console.log("Connected as:", account.name);
});

bot.command("hello", (ctx) => {
  ctx.reply("Hello from MongoAuth!");
});

await bot.launch();

Advanced Configuration

MongoDB Atlas

Connect to MongoDB Atlas for cloud-hosted storage:
import { Bot, MongoAuth } from "wapi";
import { MongoClient, ServerApiVersion } from "mongodb";
import { randomUUID } from "node:crypto";

const uri = `mongodb+srv://${process.env.MONGO_USER}:${process.env.MONGO_PASS}@cluster.mongodb.net/?retryWrites=true&w=majority`;

const client = new MongoClient(uri, {
  serverApi: {
    version: ServerApiVersion.v1,
    strict: true,
    deprecationErrors: true,
  },
});

await client.connect();
const db = client.db("production");
const collection = db.collection("wapi_sessions");

const auth = new MongoAuth(randomUUID(), collection);
const bot = new Bot({ auth });

await bot.launch();

Replica Sets

Connect to MongoDB replica set for high availability:
import { Bot, MongoAuth } from "wapi";
import { MongoClient } from "mongodb";
import { randomUUID } from "node:crypto";

const uri = "mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplicaSet";

const client = new MongoClient(uri, {
  readPreference: "primaryPreferred",
  w: "majority",
  retryWrites: true,
});

await client.connect();
const db = client.db("wapi");
const collection = db.collection("sessions");

const auth = new MongoAuth(randomUUID(), collection);
const bot = new Bot({ auth });

await bot.launch();

Session Analytics

Implement analytics using MongoDB aggregation:
// Count sessions by creation date
const sessionsByDate = await collection.aggregate([
  {
    $group: {
      _id: { $dateToString: { format: "%Y-%m-%d", date: "$_id" } },
      count: { $sum: 1 },
    },
  },
  { $sort: { _id: -1 } },
]).toArray();

// Find largest sessions
const largestSessions = await collection.aggregate([
  {
    $group: {
      _id: "$uuid",
      documentCount: { $sum: 1 },
      totalSize: { $sum: { $bsonSize: "$$ROOT" } },
    },
  },
  { $sort: { totalSize: -1 } },
  { $limit: 10 },
]).toArray();

console.log("Largest sessions:", largestSessions);

Advantages

✅ Durable storage
✅ Backup & restore
✅ Point-in-time recovery
✅ Data retention policies
✅ Archive capabilities

Best Practices

Follow these recommendations for optimal performance and reliability:

1. Indexing Strategy

// Create compound index for lookups
await collection.createIndex(
  { uuid: 1, key: 1 },
  { unique: true, background: true }
);

// Create index for bulk operations
await collection.createIndex(
  { uuid: 1 },
  { background: true }
);

2. Connection Reuse

// ✅ Good: Reuse MongoDB client
const client = await MongoClient.connect(uri);
const collection = client.db("wapi").collection("sessions");

const auth1 = new MongoAuth(uuid1, collection);
const auth2 = new MongoAuth(uuid2, collection);

// ❌ Bad: Create new connection per bot
const auth1 = new MongoAuth(
  uuid1,
  (await MongoClient.connect(uri)).db("wapi").collection("sessions")
);

3. Error Handling

try {
  await client.connect();
  await client.db("admin").command({ ping: 1 });
  console.log("MongoDB connected successfully");
} catch (error) {
  console.error("MongoDB connection failed:", error);
  process.exit(1);
}

4. Data Cleanup

// Remove stale sessions periodically
setInterval(async () => {
  const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // 30 days
  
  const result = await collection.deleteMany({
    _id: { $lt: cutoffDate },
  });
  
  console.log(`Cleaned up ${result.deletedCount} stale documents`);
}, 24 * 60 * 60 * 1000); // Daily

Troubleshooting

Connection Issues

Performance Issues


When to Use

✅ Long-term persistence
✅ Audit trail requirements
✅ Complex querying needs
✅ Centralized management
✅ Existing MongoDB infrastructure
✅ Session analytics
✅ Multi-tenant applications

See Also

Build docs developers (and LLMs) love