Dapr Cryptography .NET SDK
Overview of the Dapr Cryptography building block for .NET
Dapr.Cryptography provides a dedicated client for performing high-performance encryption and decryption operations with Dapr. The DaprEncryptionClient supports streaming operations that can handle data of any size, offloading the cryptographic work to the Dapr runtime and its configured cryptography components.
The client is registered with dependency injection via AddDaprEncryptionClient() and can be configured from IConfiguration, environment variables, or a DaprEncryptionClientBuilder for advanced scenarios.
Core concepts
Next steps
1 - Dapr Cryptography Client
Learn how to create Dapr Cryptography clients
The Dapr Cryptography package allows you to perform encryption and decryption operations provided by the Dapr sidecar.
Lifetime management
A DaprEncryptionClient is a version of the Dapr client that is dedicated to interacting with the Dapr Cryptography API.
It can be registered alongside a DaprClient and other Dapr clients without issue.
It maintains access to networking resources in the form of TCP sockets used to communicate with the Dapr sidecar.
For best performance, create a single long-lived instance of DaprEncryptionClient and provide access to that shared
instance throughout your application. DaprEncryptionClient instances are thread-safe and intended to be shared.
This can be aided by utilizing the dependency injection functionality. The registration method supports registration
as a singleton, a scoped instance, or as a transient (meaning it’s recreated every time it’s injected), but also enables
registration to utilize values from an IConfiguration or other injected service in a way that’s impractical when creating
the client from scratch in each of your classes.
Avoid creating a DaprEncryptionClient for each operation.
Configuring DaprEncryptionClient via DaprEncryptionClientBuilder
A DaprEncryptionClient can be configured by invoking methods on the DaprEncryptionClientBuilder class before calling
.Build() to create the client itself. The settings for each DaprEncryptionClientBuilder are separate can cannot be
changed after calling .Build().
var daprEncryptionClient = new DaprEncryptionClientBuilder()
.UseDaprApiToken("abc123") //Specify the API token used to authenticate to the Dapr sidecar
.Build();
The DaprEncryptionClientBuilder contains settings for:
- The HTTP endpoint of the Dapr sidecar
- The gRPC endpoint of the Dapr sidecar
- The
JsonSerializerOptions object used to configure JSON serialization - The
GrpcChannelOptions object used to configure gRPC - The API token used to authenticate requests to the sidecar
- The factory method used to create the
HttpClient instance used by the SDK - The timeout used for the
HttpClient instance when making requests to the sidecar
The SDK will read the following environment variables to configure the default values:
DAPR_HTTP_ENDPOINT: used to find the HTTP endpoint of the Dapr sidecar, example: https://dapr-api.mycompany.comDAPR_GRPC_ENDPOINT: used to find the gRPC endpoint of the Dapr sidecar, example: https://dapr-grpc-api.mycompany.comDAPR_HTTP_PORT: if DAPR_HTTP_ENDPOINT is not set, this is used to find the HTTP local endpoint of the Dapr sidecarDAPR_GRPC_PORT: if DAPR_GRPC_ENDPOINT is not set, this is used to find the gRPC local endpoint of the Dapr sidecarDAPR_API_TOKEN: used to set the API token
Configuring gRPC channel options
Dapr’s use of CancellationToken for cancellation relies on the configuration of the gRPC channel options. If you need
to configure these options yourself, make sure to enable the ThrowOperationCanceledOnCancellation setting.
var daprEncryptionClient = new DaprEncryptionClientBuilder()
.UseGrpcChannelOptions(new GrpcChannelOptions { ThrowOperationCanceledOnCancellation = true })
.Build();
Using cancellation with DaprEncryptionClient
The APIs on DaprEncryptionClient perform asynchronous operations and accept an optional CancellationToken parameter. This
follows a standard .NET practice for cancellable operations. Note that when cancellation occurs, there is no guarantee that
the remote endpoint stops processing the request, only that the client has stopped waiting for completion.
When an operation is canceled, it can throw an OperationCanceledException. Stream failures are surfaced while
enumerating results; see streaming and operation options.
Configuring DaprEncryptionClient via dependency injection
Using the built-in extension methods for registering the DaprEncryptionClient in a dependency injection container can
provide the benefit of registering the long-lived service a single time, centralize complex configuration and improve
performance by ensuring similarly long-lived resources are re-purposed when possible (e.g. HttpClient instances).
There are three overloads available to give the developer the greatest flexibility in configuring the client for their
scenario. Each of these will register the IHttpClientFactory on your behalf if not already registered, and configure
the DaprEncryptionClientBuilder to use it when creating the HttpClient instance in order to re-use the same instance as
much as possible and avoid socket exhaustion and other issues.
In the first approach, there’s no configuration done by the developer and the DaprEncryptionClient is configured with the
default settings.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDaprEncryptionClient();
var app = builder.Build();
Sometimes the developer will need to configure the created client using the various configuration options detailed
above. This is done through an overload that passes in the DaprEncryptionClientBuiler and exposes methods for configuring
the necessary options.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDaprEncryptionClient((_, daprEncryptionClientBuilder) => {
//Set the API token
daprEncryptionClientBuilder.UseDaprApiToken("abc123");
//Specify a non-standard HTTP endpoint
daprEncryptionClientBuilder.UseHttpEndpoint("http://dapr.my-company.com");
});
var app = builder.Build();
Finally, it’s possible that the developer may need to retrieve information from another service in order to populate
these configuration values. That value may be provided from a DaprClient instance, a vendor-specific SDK or some
local service, but as long as it’s also registered in DI, it can be injected into this configuration operation via the
last overload:
var builder = WebApplication.CreateBuilder(args);
//Register a fictional service that retrieves secrets from somewhere
builder.Services.AddSingleton<SecretService>();
builder.Services.AddDaprEncryptionClient((serviceProvider, daprEncryptionClientBuilder) => {
//Retrieve an instance of the `SecretService` from the service provider
var secretService = serviceProvider.GetRequiredService<SecretService>();
var daprApiToken = secretService.GetSecret("DaprApiToken").Value;
//Configure the `DaprEncryptionClientBuilder`
daprEncryptionClientBuilder.UseDaprApiToken(daprApiToken);
});
var app = builder.Build();
2 - How to: Create and use Dapr Cryptography in the .NET SDK
Learn how to create and use the Dapr Cryptography client using the .NET SDK
Prerequisites
Installation
.NET framework support
Be advised that .NET 8 and .NET 9 reach end of support in November 2026. Support for both will be dropped
in Dapr v1.20; only .NET 10 and .NET 11 will be supported through the end of 2027.To get started with the Dapr Cryptography client, install the
Dapr.Cryptography package from NuGet:
dotnet add package Dapr.Cryptography
These examples target SDK 1.19.0 or later. Configure a cryptography component and a key supported by
that component before running them. Import Dapr.Cryptography.Encryption,
Dapr.Cryptography.Encryption.Models, and Dapr.Cryptography.Encryption.Extensions.
The client is experimental (DAPR_CRYPTOGRAPHY).
A DaprEncryptionClient maintains access to networking resources in the form of TCP sockets used to communicate with
the Dapr sidecar.
Dependency Injection
The AddDaprEncryptionClient() method will register the Dapr client with dependency injection and is the recommended approach
for using this package. This method accepts an optional options delegate for configuring the DaprEncryptionClient and a
ServiceLifetime argument, allowing you to specify a different lifetime for the registered services instead of the default Singleton
value.
The following example assumes all default values are acceptable and is sufficient to register the DaprEncryptionClient:
services.AddDaprEncryptionClient();
The optional configuration delegate is used to configure the DaprEncryptionClient by specifying options on the
DaprEncryptionClientBuilder as in the following example:
services.AddSingleton<DefaultOptionsProvider>();
services.AddDaprEncryptionClient((serviceProvider, clientBuilder) => {
//Inject a service to source a value from
var optionsProvider = serviceProvider.GetRequiredService<DefaultOptionsProvider>();
var standardTimeout = optionsProvider.GetStandardTimeout();
//Configure the value on the client builder
clientBuilder.UseTimeout(standardTimeout);
});
Manual Instantiation
Rather than using dependency injection, a DaprEncryptionClient can also be built using the static client builder.
For best performance, create a single long-lived instance of DaprEncryptionClient and provide access to that shared instance throughout
your application. DaprEncryptionClient instances are thread-safe and intended to be shared.
Avoid creating a DaprEncryptionClient per-operation.
A DaprEncryptionClient can be configured by invoking methods on the DaprEncryptionClientBuilder class before calling .Build()
to create the client. The settings for each DaprEncryptionClient are separate and cannot be changed after calling .Build().
var daprEncryptionClient = new DaprEncryptionClientBuilder()
.UseGrpcEndpoint("http://localhost:50001")
.Build();
See the .NET documentation here for more information about the options available when configuring the Dapr client via the builder.
Try it out
Put the Dapr Cryptography .NET SDK to the test. Walk through the samples to see Dapr in action:
| SDK Samples | Description |
|---|
| SDK samples | Clone the SDK repo to try out some examples and get started. |
Encrypt and decrypt buffered content
The byte overloads accept and return ReadOnlyMemory<byte>. They buffer the complete output, so use them
for content that fits in memory:
using System.Text;
using Dapr.Cryptography.Encryption.Models;
var options = new EncryptionOptions(KeyWrapAlgorithm.RsaOaep256)
{
EncryptionCipher = DataEncryptionCipher.AesGcm
};
var ciphertext = await daprEncryptionClient.EncryptAsync(
"cryptostore", Encoding.UTF8.GetBytes("Sensitive content"), "encryption-key",
options, cancellationToken);
var plaintext = await daprEncryptionClient.DecryptAsync(
"cryptostore", ciphertext, "encryption-key", cancellationToken: cancellationToken);
Choose a key-wrap algorithm supported by your configured key and component. The SDK exposes AES key-wrap
(Aes, A256kw), AES-CBC (A128cbc, A192cbc, A256cbc), and RSA (Rsa, RsaOaep256) choices;
exposing an enum value does not guarantee that every cryptography component supports it.
Encrypt and decrypt streams
The stream overloads return IAsyncEnumerable<ReadOnlyMemory<byte>>. Consume all output chunks and write
them to your destination instead of buffering the file:
await using (var source = File.OpenRead("report.pdf"))
await using (var encrypted = File.Create("report.pdf.enc"))
{
await foreach (var chunk in daprEncryptionClient.EncryptAsync(
"cryptostore", source, "encryption-key", options, cancellationToken))
{
await encrypted.WriteAsync(chunk, cancellationToken);
}
}
await using (var encrypted = File.OpenRead("report.pdf.enc"))
await using (var destination = File.Create("report-restored.pdf"))
{
await foreach (var chunk in daprEncryptionClient.DecryptAsync(
"cryptostore", encrypted, "encryption-key", cancellationToken: cancellationToken))
{
await destination.WriteAsync(chunk, cancellationToken);
}
}
The caller owns the input and destination streams. Enumeration completes after both request and response
processing finish. Errors can occur while enumerating, not just when obtaining the enumerable. Disposing the
enumerator early cancels processing and waits for it to stop; do not treat a partial output file as a complete
encrypted or decrypted document.
Encryption and decryption options
| Setting | Behavior |
|---|
EncryptionOptions.KeyWrapAlgorithm | Required constructor argument; selects the key-wrap algorithm. |
EncryptionOptions.EncryptionCipher | AesGcm by default, or ChaCha20Poly1305. |
EncryptionOptions.DecryptionKeyName | Optional key name/version to record for decryption. If omitted, the SDK asks the runtime to omit the decryption key name from the encrypted header. Supply the key when decrypting. |
EncryptionOptions.StreamingBlockSizeInBytes | Upload block size, 4 KiB by default; must be positive and generally should not exceed 64 KiB. |
DecryptionOptions.StreamingBlockSizeInBytes | Decryption upload block size, also 4 KiB by default and required to be positive. |
DecryptAsync accepts optional DecryptionOptions. Cryptography operates on bytes, not JSON, regardless
of the shared builder’s JSON serialization options. The dedicated client implements streaming encryption
and decryption; it does not expose key retrieval, signing, verification, or the runtime’s other subtle APIs.
Errors and cancellation
Pass a cancellation token through both client calls and destination writes. gRPC and stream-processing failures
must be observed while awaiting or enumerating the result; they are not successful empty outputs. Cancellation
or a failed stream does not remove any partial destination file your application has already written.