Skip to content

MongoDB

Tayra integrates with MongoDB through TayraMongoCollection<T> -- a lightweight wrapper around IMongoCollection<T> that transparently encrypts [PersonalData] fields on write and decrypts them on read. Dramatically simpler than MongoDB's native Client-Side Field Level Encryption (CSFLE), Tayra's attribute-driven approach requires no JSON schema configuration, no mongocryptd process, and works with any MongoDB deployment -- not just Atlas or Enterprise.

Prerequisites

Tayra.MongoDB requires the MongoDB.Driver 2.21+ NuGet package. Any MongoDB server version supported by the driver is compatible (MongoDB 4.4+).

Install

shell
dotnet add package Tayra.MongoDB
powershell
Install-Package Tayra.MongoDB

Setup

There are two ways to register Tayra with MongoDB: through dependency injection or directly on a collection instance.

Register Tayra core services, a key store, and the MongoDB integration in your DI container:

csharp
services.AddTayra(opts => opts.LicenseKey = licenseKey); // defaults to InMemoryKeyStore; use PostgreSQL, Vault, etc. in production

services.AddTayraMongoDB(opts =>
{
    opts.EncryptOnWrite = true;  // default
    opts.DecryptOnRead = true;   // default
});

Inject TayraMongoCollectionFactory to create wrapped collections:

csharp
public class CustomerRepository
{
    private readonly TayraMongoCollection<CustomerDocument> _customers;

    public CustomerRepository(
        IMongoDatabase database,
        TayraMongoCollectionFactory factory)
    {
        var collection = database.GetCollection<CustomerDocument>("customers");
        _customers = factory.Wrap(collection);
    }

    public async Task CreateAsync(CustomerDocument customer)
    {
        await _customers.InsertOneAsync(customer);
        // customer.Name and customer.Email are encrypted in MongoDB
        // but the in-memory object retains cleartext values
    }
}

Collection-Based Setup

If you prefer to wrap collections directly (e.g., in a console app or outside of DI), call WithTayra() on any IMongoCollection<T>:

csharp
var tayra = serviceProvider.GetRequiredService<ITayra>();

var mongoClient = new MongoClient("mongodb://localhost:27017");
var database = mongoClient.GetDatabase("myapp");
var collection = database.GetCollection<CustomerDocument>("customers");

var tayraCollection = collection.WithTayra(tayra);

You can also pass options:

csharp
var tayraCollection = collection.WithTayra(fieldEncrypter, new TayraMongoOptions
{
    EncryptOnWrite = true,
    DecryptOnRead = true,
});

When to Use Collection-Based vs DI

Use the DI-based setup when you have a standard ASP.NET Core or hosted service application. Use the collection-based setup when you need fine-grained control, are configuring collections outside of DI, or want different options per collection.

Options

csharp
services.AddTayraMongoDB(opts =>
{
    opts.EncryptOnWrite = true;  // default
    opts.DecryptOnRead = true;   // default
});
PropertyTypeDefaultDescription
EncryptOnWritebooltrueEncrypt [PersonalData] fields before writing documents to MongoDB
DecryptOnReadbooltrueDecrypt [PersonalData] fields after reading documents from MongoDB

Define Your Document

Annotate your MongoDB document classes with [DataSubjectId] and [PersonalData]:

csharp
public class CustomerDocument
{
    public Guid Id { get; set; }

    [DataSubjectId]
    public string SubjectId { get; set; } = "";

    [PersonalData]
    public string Name { get; set; } = "";

    [PersonalData(MaskValue = "redacted@example.com")]
    public string Email { get; set; } = "";

    public string AccountType { get; set; } = ""; // Not encrypted
}
  • [DataSubjectId] on SubjectId identifies the data owner and determines the encryption key.
  • [PersonalData] on Name and Email marks them for encryption.
  • The MaskValue parameter on Email specifies the value returned after crypto-shredding.
  • AccountType has no attribute and is stored as plaintext in MongoDB.

Wrapped Operations

TayraMongoCollection<T> wraps the most common IMongoCollection<T> operations with transparent encryption and decryption:

Write Operations

csharp
// Insert a single document -- PII encrypted before write
await tayraCollection.InsertOneAsync(customer);

// Insert multiple documents -- PII encrypted before write
await tayraCollection.InsertManyAsync(customers);

// Replace a document -- PII encrypted before write
await tayraCollection.ReplaceOneAsync(
    c => c.Id == customer.Id, customer);

Read Operations

csharp
// Find a single document -- PII decrypted after read
var customer = await tayraCollection.FindOneAsync(
    c => c.SubjectId == "cust-42");

// Find multiple documents -- PII decrypted after read
var customers = await tayraCollection.FindAsync(
    c => c.AccountType == "Premium");

Delete and Count Operations

csharp
// Delete a document -- no encryption needed
await tayraCollection.DeleteOneAsync(c => c.Id == customerId);

// Delete multiple documents
await tayraCollection.DeleteManyAsync(c => c.AccountType == "Inactive");

// Count documents
var count = await tayraCollection.CountDocumentsAsync(
    c => c.AccountType == "Premium");

Accessing the Inner Collection

For operations not wrapped by TayraMongoCollection<T> (e.g., aggregation pipelines, bulk writes, index management), access the underlying IMongoCollection<T> via the Inner property:

csharp
// Use the unwrapped collection for unsupported operations
var pipeline = tayraCollection.Inner
    .Aggregate()
    .Group(c => c.AccountType, g => new { Type = g.Key, Count = g.Count() });

Unwrapped Access

Operations performed through .Inner bypass Tayra's encryption and decryption. PII fields in documents returned by unwrapped operations will contain AES-256-GCM ciphertext.

How It Works

TayraMongoCollection<T> intercepts collection operations at the wrapper level:

  1. Write operations -- Before writing a document to MongoDB, the wrapper encrypts all [PersonalData] fields using the encryption key derived from the [DataSubjectId] value. After the write completes, it decrypts the in-memory object back to cleartext so your application code continues working with plaintext values.

  2. Read operations -- After reading a document from MongoDB, the wrapper decrypts all [PersonalData] fields. The returned document contains cleartext values.

  3. Delete and count operations -- These pass through to the underlying collection without encryption or decryption, since they do not read or write document content.

Performance Note

The crypto engine caches encryption keys in memory after the initial fetch from the key store. After warmup, most encrypt and decrypt operations are memory-only lookups with no key store round trips. For high-throughput workloads, the overhead is typically sub-microsecond per field.

Crypto-Shredding

GDPR Article 17 "right to be forgotten" is implemented via crypto-shredding. Instead of finding and deleting every document containing a person's data across all collections, you delete their encryption key. All encrypted fields become permanently unreadable:

csharp
// Delete the data subject's encryption keys
await cryptoEngine.DeleteAllKeysAsync("cust-42");

// Subsequent reads return replacement values
var shredded = await tayraCollection.FindOneAsync(
    c => c.SubjectId == "cust-42");
// shredded.Name == ""
// shredded.Email == "redacted@example.com"

The documents remain in MongoDB (preserving referential integrity, audit trails, and non-PII fields like AccountType), but the PII fields are permanently unreadable.

Irreversible

Crypto-shredding is permanent. The encryption key is deleted from the key store and cannot be recovered. The original data is lost forever.

Comparison with MongoDB CSFLE

FeatureTayra.MongoDBMongoDB CSFLE
SetupAdd attributes to your modelConfigure JSON schema, key vault, mongocryptd
Server requirementsAny MongoDB deploymentAtlas or Enterprise only (for automatic encryption)
Encryption scopeApplication-level, per-fieldDriver-level, per-field
Key managementTayra key stores (PostgreSQL, Vault, Azure, AWS)MongoDB Key Vault (Atlas KMS, AWS, Azure, GCP)
Crypto-shreddingBuilt-in via key deletionManual key rotation
GDPR complianceBuilt-in attributes and erasure patternsRequires custom implementation
Additional processesNonemongocryptd or crypt_shared library

See Also