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 3.x 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:

cs
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
});
anchor

AddTayraMongoDB registers TayraMongoOptions as a singleton. Inject it together with ITayra and wrap each collection with WithTayra():

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

    public CustomerRepository(
        IMongoDatabase database,
        ITayra tayra,
        TayraMongoOptions options) // registered by AddTayraMongoDB
    {
        var collection = database.GetCollection<CustomerDocument>("customers");
        _customers = collection.WithTayra(tayra, options);
    }

    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
    }
}
anchor

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>:

cs
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);
anchor

You can also pass options:

cs
var tayraCollection = collection.WithTayra(tayra, new TayraMongoOptions
{
    EncryptOnWrite = true,
    DecryptOnRead = true,
});
anchor

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 ​

cs
services.AddTayraMongoDB(opts =>
{
    opts.EncryptOnWrite = true;  // default
    opts.DecryptOnRead = true;   // default
});
anchor
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]:

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

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

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

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

    public string AccountType { get; set; } = ""; // Not encrypted
}
anchor
  • [DataSubjectId] on SubjectId identifies the data owner and determines the encryption key.
  • [PersonalData] on Name and Email marks them for encryption.
  • The ReplacementValue 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. The wrapped methods take a FilterDefinition<T>, so build filters with Builders<T>.Filter (a bare lambda does not convert to FilterDefinition<T>):

Write Operations ​

cs
// 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(
    Builders<CustomerDocument>.Filter.Where(c => c.Id == customer.Id), customer);
anchor

Read Operations ​

cs
// Find a single document: PII decrypted after read
var customer = await tayraCollection.FindOneAsync(
    Builders<CustomerDocument>.Filter.Where(c => c.SubjectId == "cust-42"));

// Find multiple documents: PII decrypted after read
var customers = await tayraCollection.FindAsync(
    Builders<CustomerDocument>.Filter.Where(c => c.AccountType == "Premium"));
anchor

Delete and Count Operations ​

cs
var filter = Builders<CustomerDocument>.Filter;

// Delete a document: no encryption needed
await tayraCollection.DeleteOneAsync(filter.Where(c => c.Id == customerId));

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

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

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:

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

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. When the write ends, it puts the object's plaintext back exactly as it was, so your application code continues working with plaintext values. That happens whether the write succeeded or failed (a duplicate key, a timeout, a dropped connection), so retrying the write encrypts the document once rather than twice.

  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:

cs
// Delete the data subject's encryption keys
await tayra.ShredAsync("cust-42");

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

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 ​