For AI agents: a documentation index is available at https://www.mongodb.com/docs/llms.txt — markdown versions of all pages are available by appending .md to any URL path.
Docs Menu

In-Use Encryption

You can use the Node.js driver to encrypt specific document fields by using a set of features called in-use encryption. In-use encryption allows your application to encrypt data before sending it to MongoDB and query documents with encrypted fields.

Warning

MongoDB 8.2 Known Issue

Version 8.2.0 of mongocryptd might not run on Windows. This bug affects In-Use Encryption with the driver if you specify the --logpath NUL argument when starting mongocryptd.

To learn more about this issue and how to resolve it, see Known Issues in the MongoDB 8.2 Release Notes.

In-use encryption prevents unauthorized users from viewing plaintext data as it is sent to MongoDB or while it is in an encrypted database. To enable in-use encryption in an application and authorize it to decrypt data, you must create encryption keys that only your application can access. Only applications that have access to your encryption keys can access the decrypted, plaintext data. If an attacker gains access to the database, they can only see the encrypted ciphertext data because they lack access to the encryption keys.

You might use in-use encryption to encrypt fields in your MongoDB documents that contain the following types of sensitive data:

  • Credit card numbers

  • Addresses

  • Health information

  • Financial information

  • Any other sensitive or personally identifiable information (PII)

MongoDB offers the following features to enable in-use encryption:

Queryable Encryption (QE) is an in-use encryption feature that lets you run queries on encrypted field values, including equality, range, and prefix, suffix, and substring queries. Range query support requires MongoDB Server 8.0 or later. Prefix, suffix, and substring query support requires MongoDB Server 9.0 or later.

To learn more about Queryable Encryption, see Queryable Encryption in the MongoDB Server manual.

Client-side Field Level Encryption (CSFLE) was introduced in MongoDB Server version 4.2 and supports searching encrypted fields for equality. CSFLE differs from Queryable Encryption in that you can select either a deterministic or random encryption algorithm to encrypt fields. You can only query encrypted fields that use a deterministic encryption algorithm when using CSFLE. When you use a random encryption algorithm to encrypt fields in CSFLE, they can be decrypted, but you cannot perform equality queries on those fields. When you use Queryable Encryption, you cannot specify the encryption algorithm, but you can query all encrypted fields.

When you deterministically encrypt a value, the same input value produces the same output value. While deterministic encryption allows you to perform queries on those encrypted fields, encrypted data with low cardinality is susceptible to code breaking by frequency analysis.

Tip

To learn more about these concepts, see the following Wikipedia entries:

To learn more about CSFLE, see CSFLE in the Server manual.

Starting in MongoDB Server 8.1, you can use the $lookup aggregation stage with clients configured for in-use encryption. This feature requires mongodb-client-encryption package version 6.3.0 or later.

The $lookup stage allows you to join related data across encrypted collections without having to fetch and combine documents manually in your application code. Both the source collection and the from collection must be configured for in-use encryption. The fields specified in localField and foreignField must not be encrypted fields.

The following example shows a $lookup operation on an encrypted collection:

const pipeline = [
{
$lookup: {
from: "encryptedCollection",
localField: "userId",
foreignField: "_id",
as: "userDetails"
}
}
];
const results = await collection.aggregate(pipeline).toArray();

Starting in Node.js driver version 7.6, you can route the requests that the Node.js driver makes to your key management system (KMS) through an HTTP proxy. Use this feature when your environment requires outbound KMS traffic to pass through an HTTP forward proxy. The proxyOptions setting supports only the SOCKS5 protocol and doesn't cover this case.

To control how the driver connects to a KMS host, set the kmsConnectCallback option on your ClientEncryptionOptions object or your AutoEncryptionOptions object. When you set this option, the driver calls your callback instead of connecting to the KMS host itself. The callback receives the following properties:

Property
Description

host

The hostname of the KMS host that the driver must reach.

port

The port of the KMS host that the driver must reach.

timeoutMS

The time remaining in the operation's client-side operation timeout (CSOT) budget, in milliseconds. This property is undefined if the operation has no CSOT configured.

signal

An AbortSignal that aborts when the connection attempt exceeds the timeout budget. When the signal fires, your callback must stop connecting and reject.

The following example defines a callback that opens a tunnel to the KMS host by sending an HTTP CONNECT request to a proxy, and then passes the callback to a ClientEncryption instance:

import * as net from "net";
const kmsConnectCallback = ({ host, port, timeoutMS, signal }) =>
new Promise((resolve, reject) => {
// Opens a plain connection to the proxy, not to the KMS host.
// Passing signal lets Node abort the connection attempt when the
// driver's timeout budget expires.
const socket = net.connect({
host: "proxy.example.com",
port: 8080,
signal
});
// Applies the remaining CSOT budget to the proxy handshake, so that
// a proxy that accepts the connection but never answers CONNECT
// can't stall the operation.
if (timeoutMS !== undefined) {
socket.setTimeout(timeoutMS, () => {
socket.destroy();
reject(new Error("Timed out waiting for the proxy"));
});
}
socket.once("error", reject);
socket.once("connect", () => {
// Asks the proxy to tunnel to the KMS host
socket.write(
`CONNECT ${host}:${port} HTTP/1.1\r\n` +
`Host: ${host}:${port}\r\n\r\n`
);
socket.once("data", chunk => {
if (chunk.toString("utf8").startsWith("HTTP/1.1 200")) {
// Clears the handshake timeout and returns the socket so that
// the driver can perform the TLS handshake
socket.setTimeout(0);
resolve(socket);
} else {
socket.destroy();
reject(new Error("Proxy refused the CONNECT request"));
}
});
});
});
const clientEncryption = new ClientEncryption(keyVaultClient, {
keyVaultNamespace,
kmsProviders,
kmsConnectCallback
});

The signal property applies to the connection to the proxy, and the timeoutMS property applies to the CONNECT exchange. A socket timeout stays active after the CONNECT exchange ends, so clear the timeout before you resolve the promise. Otherwise, the timeout can destroy the socket while the driver performs the TLS handshake.

The preceding example is condensed to show the sequence of calls. In production code, buffer the proxy's response until you receive the end of the header block, because the response can arrive across multiple chunks.

Important

The kmsConnectCallback and proxyOptions options are mutually exclusive. If you set kmsConnectCallback and specify a proxyHost value in proxyOptions, the driver raises a MongoCryptInvalidArgumentError.