Dosaic.Plugins.Persistence.VaultSharp 1.2.18

dotnet add package Dosaic.Plugins.Persistence.VaultSharp --version 1.2.18
                    
NuGet\Install-Package Dosaic.Plugins.Persistence.VaultSharp -Version 1.2.18
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Dosaic.Plugins.Persistence.VaultSharp" Version="1.2.18" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Dosaic.Plugins.Persistence.VaultSharp" Version="1.2.18" />
                    
Directory.Packages.props
<PackageReference Include="Dosaic.Plugins.Persistence.VaultSharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Dosaic.Plugins.Persistence.VaultSharp --version 1.2.18
                    
#r "nuget: Dosaic.Plugins.Persistence.VaultSharp, 1.2.18"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Dosaic.Plugins.Persistence.VaultSharp@1.2.18
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Dosaic.Plugins.Persistence.VaultSharp&version=1.2.18
                    
Install as a Cake Addin
#tool nuget:?package=Dosaic.Plugins.Persistence.VaultSharp&version=1.2.18
                    
Install as a Cake Tool

Dosaic.Plugins.Persistence.VaultSharp

Dosaic.Plugins.Persistence.VaultSharp is a Dosaic plugin that integrates HashiCorp Vault for secure secret storage. It provides a typed ISecretStorage<TBucket> abstraction backed either by a live Vault server (KV v2 + TOTP engines) or a local filesystem (useful for development and testing without a running Vault instance).

Installation

dotnet add package Dosaic.Plugins.Persistence.VaultSharp

or add as a package reference to your .csproj:

<PackageReference Include="Dosaic.Plugins.Persistence.VaultSharp" Version=""/>

Configuration

The plugin is configured via the vault section in appsettings.yml / appsettings.json. The section is bound to VaultConfiguration using the [Configuration("vault")] attribute.

Vault server mode

vault:
  url: "http://localhost:8200"
  token: "your-vault-token"
  totpIssuer: "MyApp"               # optional — default: Dosaic.Plugins.Persistence.VaultSharp
  totpPeriodInSeconds: 30            # optional — default: 30

Local filesystem mode (development / testing)

When useLocalFileSystem is true, secrets are stored as JSON files under localFileSystemPath. No Vault server is required. TOTP codes are generated locally using RFC 6238 (HMAC-SHA1).

vault:
  useLocalFileSystem: true
  localFileSystemPath: "./nodep-vault"   # optional — default: ./nodep-vault
  totpPeriodInSeconds: 30                # optional — default: 30

VaultConfiguration properties

Property Type Default Description
Url string "" Vault server base URL
Token string "" Token used to authenticate with Vault
TotpIssuer string "Dosaic.Plugins.Persistence.VaultSharp" Issuer label stored in the TOTP key
TotpPeriodInSeconds int 30 TOTP counter period in seconds
UseLocalFileSystem bool false Store secrets on the local filesystem instead of Vault
LocalFileSystemPath string "./nodep-vault" Root folder for local filesystem secrets

Vault mount points

The plugin uses two fixed Vault secret engine mount points:

Engine Mount
KV v2 credentials
TOTP totp

Both engines must exist in Vault before the application starts.

Registration

With Dosaic WebHost (automatic)

When using PluginWebHostBuilder, the plugin is discovered automatically and VaultConfiguration is resolved from IConfiguration. You only need to register your secret storage buckets — typically in your own plugin or startup code:

services.AddSecretStorage<SecretBucket>();

Without Dosaic WebHost (manual)

services.AddVaultSharpPlugin(new VaultConfiguration
{
    Url = "http://localhost:8200",
    Token = "your-vault-token"
});

services.AddSecretStorage<SecretBucket>();

For local filesystem storage without a Vault server:

var config = new VaultConfiguration { UseLocalFileSystem = true, LocalFileSystemPath = "./nodep-vault" };
services.AddLocalFileSystemSecretStorage<SecretBucket>(config);

Usage

Defining a secret bucket

Buckets are plain enums that categorise secrets stored in Vault:

public enum SecretBucket
{
    ApiKeys = 0,
    DatabaseCredentials = 1,
    ServiceAccounts = 2
}

ISecretStorage<TBucket> interface

public interface ISecretStorage<TSecretBucket> where TSecretBucket : struct, Enum
{
    Task<Secret> GetSecretAsync(SecretId<TSecretBucket> secretId, CancellationToken cancellationToken = default);
    Task<SecretId<TSecretBucket>> CreateSecretAsync(TSecretBucket bucket, Secret secret, CancellationToken cancellationToken = default);
    Task<SecretId<TSecretBucket>> UpdateSecretAsync(SecretId<TSecretBucket> secretId, Secret secret, CancellationToken cancellationToken = default);
    Task DeleteSecretAsync(SecretId<TSecretBucket> secretId, CancellationToken cancellationToken = default);
}

Inject it via the constructor:

public class MyService(ISecretStorage<SecretBucket> secrets)
{
    // ...
}

SecretId<TBucket>

SecretId<TBucket> is a read-only struct that identifies a stored secret. It encodes the bucket, type and a unique key into a URL-safe Sqid string via the Id property.

// Create a new random ID for a bucket + type combination
var id = SecretId<SecretBucket>.New(SecretBucket.DatabaseCredentials, SecretType.UsernamePassword);

// Encode / decode the opaque string representation
string opaqueId = id.Id;
var same = SecretId<SecretBucket>.FromSqid(opaqueId);

// Safe parsing (e.g. from user input)
if (SecretId<SecretBucket>.TryParse(input, out var parsed))
    Console.WriteLine(parsed.Bucket); // DatabaseCredentials

Secret types

All secret types derive from the abstract record Secret.

UsernamePasswordSecret
var secret = new UsernamePasswordSecret("admin", "s3cr3t");

var id = await secrets.CreateSecretAsync(SecretBucket.DatabaseCredentials, secret);
var retrieved = (UsernamePasswordSecret)await secrets.GetSecretAsync(id);
Console.WriteLine(retrieved.Username); // admin
UsernamePasswordApiKeySecret

Extends UsernamePasswordSecret with an additional ApiKey field.

var secret = new UsernamePasswordApiKeySecret("svc-account", "p@ssw0rd", "api-key-abc123");

var id = await secrets.CreateSecretAsync(SecretBucket.ApiKeys, secret);
var retrieved = (UsernamePasswordApiKeySecret)await secrets.GetSecretAsync(id);
Console.WriteLine(retrieved.ApiKey); // api-key-abc123
UsernamePasswordTotpSecret

Stores a username, password, and a TOTP key. On create / update the Totp must contain a TotpKey with the Base32-encoded seed. On read the Totp is populated with a TotpCode containing the current OTP, its expiry time and remaining seconds.

// Write — provide the Base32 seed key
var secret = new UsernamePasswordTotpSecret(
    "admin",
    "p@ssw0rd",
    new Totp(null, new TotpKey("JBSWY3DPEHPK3PXP"))
);
var id = await secrets.CreateSecretAsync(SecretBucket.ServiceAccounts, secret);

// Read — the live TOTP code is resolved automatically
var retrieved = (UsernamePasswordTotpSecret)await secrets.GetSecretAsync(id);
Console.WriteLine(retrieved.Totp.TotpCode.Code);             // e.g. "482910"
Console.WriteLine(retrieved.Totp.TotpCode.RemainingSeconds); // seconds until code expires
Console.WriteLine(retrieved.Totp.TotpCode.ValidTillUtc);     // UTC expiry timestamp
CertificateSecret
var secret = new CertificateSecret("-----BEGIN CERTIFICATE-----\n...", "optional-passphrase");

var id = await secrets.CreateSecretAsync(SecretBucket.ServiceAccounts, secret);
var retrieved = (CertificateSecret)await secrets.GetSecretAsync(id);
Console.WriteLine(retrieved.Certificate);

Updating and deleting secrets

// Update in-place — the SecretId stays the same
var updated = new UsernamePasswordSecret("admin", "new-password");
await secrets.UpdateSecretAsync(id, updated);

// Delete
await secrets.DeleteSecretAsync(id);

Local TOTP code generation (TotpCodeGenerator)

TotpCodeGenerator is a static helper that generates TOTP codes locally (RFC 6238, HMAC-SHA1) without calling Vault. It is used internally by LocalFileSystemSecretStorage but is also available for direct use:

// Generate a 6-digit TOTP code from a Base32 key
string code = TotpCodeGenerator.Generate("JBSWY3DPEHPK3PXP", periodInSeconds: 30);

// Get remaining seconds and expiry for the current period
var (remaining, validUntil) = TotpCodeGenerator.GetPeriodInfo(periodInSeconds: 30);

Features

  • Typed secret buckets — secrets are namespaced by a user-defined enum; different bucket enums compile to different ISecretStorage<T> registrations
  • Four secret typesUsernamePassword, UsernamePasswordApiKey, UsernamePasswordTotp, Certificate
  • Opaque secret IDs — bucket, type and key are encoded into a URL-safe Sqid string for safe external exposure
  • First-class TOTP support — creates/manages TOTP keys in Vault's TOTP engine; decodes live OTP codes on every read
  • Local filesystem backend — drop-in replacement for local development and testing; TOTP codes generated locally via RFC 6238
  • OpenTelemetry tracing — all storage operations are wrapped in ActivitySource spans with secret.bucket, secret.key, and secret.type tags
  • Readiness health checkvault (Vault HTTP health endpoint) or vault-local-filesystem (directory write probe) registered automatically as a readiness check
  • Dosaic WebHost integration — discovered and wired automatically by the source generator; no manual bootstrap required when using PluginWebHostBuilder

Health Checks

The plugin registers a readiness health check automatically:

Mode Check name Probe
Vault server vault GET /v1/sys/health via IVaultClient
Local filesystem vault-local-filesystem Creates and deletes a .health-probe file in LocalFileSystemPath

Both checks report Unhealthy on failure, preventing the application from receiving traffic until the backend is reachable.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.18 29 4/2/2026
1.2.17 59 4/1/2026
1.2.16 58 4/1/2026
1.2.15 75 3/31/2026
1.2.14 81 3/30/2026
1.2.13 78 3/26/2026
1.2.12 79 3/24/2026
1.2.11 92 3/17/2026
1.2.10 89 3/16/2026
1.2.9 84 3/13/2026
1.2.8 90 3/9/2026
1.2.7 88 3/4/2026
1.2.6 89 2/19/2026
1.2.5 84 2/17/2026
1.2.4 115 2/13/2026
1.2.3 108 1/27/2026
1.2.2 304 12/16/2025
1.2.1 282 12/16/2025
1.2.0 446 12/11/2025
1.1.21 452 12/10/2025
Loading failed