Skip to content

Data protection

To be able to run behind a load balancer the key crypting cookies and anti-CSRF mechanism must be share by all servers or the load balancer must use a session affinity mechanism.
The DataProtectionOptions section configure the ASP.NET Core Data Protection :

minimum configuration sample

"DataProtectionOptions": {
  "StorageKind": "EntityFramework"
}

full configuration sample

"DataProtectionOptions": {
  "StorageKind": "FileSytem",
  "StorageConnectionString": "C:\\data-protection-keys",
  "KeyProtectionOptions": {
    "KeyProtectionKind": "X509",
    "X509CertificatePath": "C:\\certifiactes\\data-protection.pfx",
    "X509CertificatePassword": "P@ssw0rd"
  },
  "KeyManagementOptions": {
    "AutoGenerateKeys": true,
    "NewKeyLifetime": "90.00:00:00"
  },
  "AuthenticatedEncryptorConfiguration" : {
    "EncryptionAlgorithm": "AES_256_CBC",
    "ValidationAlgorithm": "HMACSHA256"
  }
}

Storages

  • StorageKind defines the storage kind to use.
  • StorageConnectionString defines how to access the storage.

The configuration support all Key storage providers

File system

  "StorageKind": "FileSytem",
  "StorageConnectionString": "C:\\data-protection-keys",

For FileSytem storage kind, the StorageConnectionString defines the path where to store keys.

Azure Storage

  "StorageKind": "AzureStorage",
  "StorageConnectionString": "<blob URI including SAS token>",

For AzureStorage storage kind, the StorageConnectionString defines the blog URI including SAS token where to store keys.

Redis

  "StorageKind": "Redis",
  "StorageConnectionString": "localhost:6379",
  "RedisKey": "DataProtection-Keys"

For Redis storage kind, the StorageConnectionString defines the redis connection string.
(optional) RedisKey defines the redis list key where to store generated keys.

Entity Framework Core

  "StorageKind": "EntityFramework"

For EntityFramework storage king, keys are store in the DataProtectionKeys table of TheIdServer database

RavenDb

  "StorageKind": "RavenDb"

For RavenDb storage king, keys are store in the DataProtectionKeys document of RavenDb database

MongoDb

  "StorageKind": "MongoDb"

For MongoDb storage king, keys are store in the DataProtectionKeys collection of MongoDb database

Registry

Only applies to Windows deployments.

  "StorageKind": "Registry",
  "StorageConnectionString": "SOFTWARE\\Sample\\keys"

For Registry storage kind, the StorageConnectionString defines the registry path where to store keys.

Keys cannot be shared across several instances of a web app using Registry store

Key protection

KeyProtectionOptions controls Key encryption at rest configuration.
The configuartion support all kind of encryption systems.

  • KeyProtectionKind defines the kind of key protection to use.

Azure Key Vault

⚠️ Important Update: TheIdServer now uses the modern Azure.Security.KeyVault.Keys SDK. The old Microsoft.Azure.KeyVault SDK is obsolete.

The simplest configuration. Works with Managed Identity in production and Azure CLI in development:

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://your-vault.vault.azure.net/keys/key-name"
  }

This automatically uses:
- Managed Identity when running on Azure
- Azure CLI credentials when developing locally (after az login)
- Visual Studio credentials when debugging
- Environment variables for CI/CD pipelines

Option 2: Service Principal with Client Secret

For explicit authentication with Service Principal:

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://your-vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultTenantId": "your-tenant-id",
    "AzureKeyVaultClientId": "your-client-id",
    "AzureKeyVaultClientSecret": "your-client-secret"
  }

⚠️ Note: AzureKeyVaultTenantId is now required when using ClientId and ClientSecret (previously optional).

Option 3: Service Principal with Certificate

More secure than client secrets:

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://your-vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultTenantId": "your-tenant-id",
    "AzureKeyVaultClientId": "your-client-id",
    "AzureKeyVaultCertificateThumbprint": "certificate-thumbprint"
  }

The certificate must be installed in the certificate store (CurrentUser\My or LocalMachine\My).

Option 4: User-Assigned Managed Identity

For Azure resources with user-assigned Managed Identity:

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://your-vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultManagedIdentityClientId": "managed-identity-client-id"
  }

Configuration by Environment

Recommended approach for multiple environments:

appsettings.json (base):

{
  "DataProtectionOptions": {
    "StorageKind": "AzureStorage",
    "StorageConnectionString": "<connection-string>",
    "KeyProtectionOptions": {
      "KeyProtectionKind": "AzureKeyVault",
      "AzureKeyVaultKeyId": "https://vault.vault.azure.net/keys/key-name"
    }
  }
}

appsettings.Development.json:

{
  "DataProtectionOptions": {
    "KeyProtectionOptions": {
      "AzureKeyVaultKeyId": "https://dev-vault.vault.azure.net/keys/dev-key"
    }
  }
}

Uses Azure CLI in development.

appsettings.Production.json:

{
  "DataProtectionOptions": {
    "KeyProtectionOptions": {
      "AzureKeyVaultKeyId": "https://prod-vault.vault.azure.net/keys/prod-key"
    }
  }
}

Uses Managed Identity in production.

Azure Key Vault Permissions

Your identity (Service Principal or Managed Identity) needs these permissions:

  • Get (keys)
  • Wrap Key
  • Unwrap Key

Configure in Azure Portal: Key Vault > Access policies

Migration from Old Configuration

Before (obsolete):

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultClientId": "client-id",
    "AzureKeyVaultClientSecret": "client-secret"
  }

After (add TenantId):

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultTenantId": "tenant-id",
    "AzureKeyVaultClientId": "client-id",
    "AzureKeyVaultClientSecret": "client-secret"
  }

Or better (use DefaultAzureCredential):

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://vault.vault.azure.net/keys/key-name"
  }

Windows DPAPI

Only applies to Windows deployments.

  "KeyProtectionOptions": {
    "KeyProtectionKind": "WindowsDpApi",
    "WindowsDPAPILocalMachine": false
  }

X.509 certificate

From certificate file :

  "KeyProtectionOptions": {
    "KeyProtectionKind": "X509",  
    "X509CertificatePath": "C:\\certificates\\theidserver.pfx",
    "X509CertificatePassword": "P@ssw0rd"
  }

If the certificate is loaded from a file, it can be selfsigned/seflencrypted and expired.

From certificate thumbprint :

  "KeyProtectionOptions": {
    "KeyProtectionKind": "X509",
    "X509CertificatePath": "3BCE558E2AD3E0E34A7743EAB5AEA2A9BD2575A0"
  }

Using the thumbprint, the certificate must be valid.

Windows DPAPI-NG

This mechanism is available only on Windows 8/Windows Server 2012 or later.

  "KeyProtectionOptions": {
    "KeyProtectionKind": "WindowsDpApiNg"
  }

Using a SID

  "KeyProtectionOptions": {
    "KeyProtectionKind": "WindowsDpApiNg"
    "WindowsDpApiNgSid": "S-1-5-21-..."
  }

Using a certificate thumbprint

  "KeyProtectionOptions": {
    "KeyProtectionKind": "WindowsDpApiNg"
    "WindowsDpApiNgCerticate": "3BCE558E2...B5AEA2A9BD2575A0"
  }

Key management

The section KeyManagementOptions congrols the Key management configuration

  "KeyManagementOptions": {
    "AutoGenerateKeys": true,
    "NewKeyLifetime": "90.00:00:00"
  }
  • AutoGenerateKeys by default keys are auto generated, you can disable auto generation with "AutoGenerateKeys": false.
  • NewKeyLifetime by default the key lifetime is 90 days. You can set your lifetime with NewKeyLifetime but it cannot be less than 1 week.

Algorithms

You can change alrorithms with the section AuthenticatedEncryptorConfiguration. It's binded to a AuthenticatedEncryptorConfiguration object.

  "AuthenticatedEncryptorConfiguration" : {
    "EncryptionAlgorithm": "AES_256_CBC",
    "ValidationAlgorithm": "HMACSHA256"
  }

Additionals resources

Authors: Olivier Lefebvre