Deneblab.StashLock.Client 0.3.109

There is a newer version of this package available.
See the version list below for details.
dotnet add package Deneblab.StashLock.Client --version 0.3.109
                    
NuGet\Install-Package Deneblab.StashLock.Client -Version 0.3.109
                    
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="Deneblab.StashLock.Client" Version="0.3.109" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Deneblab.StashLock.Client" Version="0.3.109" />
                    
Directory.Packages.props
<PackageReference Include="Deneblab.StashLock.Client" />
                    
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 Deneblab.StashLock.Client --version 0.3.109
                    
#r "nuget: Deneblab.StashLock.Client, 0.3.109"
                    
#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 Deneblab.StashLock.Client@0.3.109
                    
#: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=Deneblab.StashLock.Client&version=0.3.109
                    
Install as a Cake Addin
#tool nuget:?package=Deneblab.StashLock.Client&version=0.3.109
                    
Install as a Cake Tool

Deneblab.StashLock.Client

Async-first .NET secrets management client for StashLock vault.

Installation

dotnet add package Deneblab.StashLock.Client

Quick Start

using Deneblab.StashLock.Client;

// From environment variable STASHLOCK_VAULT_KEY
var store = await StashLock.CreateClient()
    .FromEnvironment()
    .OpenAsync();

var dbPassword = store["Database:Password"];

Fluent API

All access starts with StashLock.CreateClient() which returns a fluent builder.

Remote vault (password-based)

// From environment variable
var store = await StashLock.CreateClient()
    .FromEnvironment()
    .OpenAsync();

// Explicit vault key
var store = await StashLock.CreateClient()
    .WithVaultKey("myapp.prod.00001.password")
    .OpenAsync();

Remote sealed-box (X25519)

var store = await StashLock.CreateClient()
    .WithBox("myapp", "prod")
    .WithPrivateKey(key)              // optional, falls back to env var
    .OpenAsync();

Sealed-box with offline cache

var store = await StashLock.CreateClient()
    .WithBox("myapp", "prod")
    .WithPrivateKey(key)
    .WithCache(ttl: TimeSpan.FromHours(2))
    .OpenAsync();

// With custom cache directory
var store = await StashLock.CreateClient()
    .WithBox("myapp", "prod")
    .WithCache(cacheDir: "/app/cache", ttl: TimeSpan.FromHours(4))
    .OpenAsync();

Local files

// Plain JSON file (development)
var store = await StashLock.CreateClient()
    .FromDevFile()                    // auto-discovers dev/secrets/secrets.json
    .OpenAsync();

// Explicit plain JSON file
var store = await StashLock.CreateClient()
    .FromFile("./secrets.json")
    .OpenAsync();

// Local encrypted file (SOPS or whole-file mode)
var store = await StashLock.CreateClient()
    .FromEncryptedFile("./stashlock.enc.prod.secrets.json")
    .WithPrivateKey(key)
    .OpenAsync();

Configuration validation

var result = await StashLock.CreateClient()
    .WithBox("myapp", "prod")
    .ValidateAsync();

if (!result.IsValid)
    foreach (var issue in result.Issues)
        Console.WriteLine($"ERROR: {issue}");

Builder options

Method Description
.FromEnvironment() Read vault key from STASHLOCK_VAULT_KEY env var
.WithVaultKey(string) Explicit vault key (box.tag.version.password)
.WithBox(box, tag, version?) Sealed-box mode with box/tag/version
.FromDevFile(path?) Plain JSON file (auto-discovers if no path)
.FromFile(path) Explicit plain JSON file
.FromEncryptedFile(path) Local encrypted file (SOPS or whole-file)
.WithApiUrl(url) Override API URL
.WithApiKey(key) Override API key
.WithPrivateKey(base64) X25519 private key for sealed-box decryption
.WithCache(cacheDir?, ttl?, machineId?) Enable encrypted offline cache
.OpenAsync() Open the secrets store
.ValidateAsync() Validate configuration without opening

Reading Secrets

// Indexer (synchronous — secrets are pre-loaded)
string value = store["Database:Password"];

// Async
string value = await store.GetAsync("Database:Password");

// TryGet (no exception on missing key)
if (store.TryGet("OptionalKey", out var value))
{
    // use value
}

// Section as dictionary
var dbConfig = await store.GetSectionAsDictionaryAsync("Database");
// Returns: { "Host": "localhost", "Password": "secret", ... }

// Typed section (deserializes into a POCO)
var dbConfig = store.GetSection<DatabaseConfig>("Database");

IConfiguration Integration

Single AddStashLock extension method with the same fluent builder:

using Deneblab.StashLock.Client.Configuration;

var builder = WebApplication.CreateBuilder(args);

// Remote sealed-box vault with cache
builder.Configuration.AddStashLock(cfg => cfg
    .WithBox("myapp", "prod")
    .WithCache(cacheDir: "/app/cache", ttl: TimeSpan.FromHours(4))
);

var app = builder.Build();

// Access secrets via standard IConfiguration
var connString = app.Configuration["Database:ConnectionString"];
var apiKey = app.Configuration["ExternalService:ApiKey"];

Dev/prod branching

builder.ConfigureAppConfiguration((ctx, config) =>
{
    if (ctx.HostingEnvironment.IsDevelopment())
    {
        config.AddStashLock(cfg => cfg
            .FromDevFile("dev/secrets/secrets.json")
        );
    }
    else
    {
        config.AddStashLock(cfg => cfg
            .WithBox("myapp", ctx.HostingEnvironment.EnvironmentName.ToLower())
            .WithCache(ttl: TimeSpan.FromHours(2))
        );
    }
});

Encrypted local file

builder.Configuration.AddStashLock(cfg => cfg
    .FromEncryptedFile("secrets.enc.json")
    .WithPrivateKey(key)
);

Dependency Injection

Register ISecretsStore as a singleton in your DI container:

using Deneblab.StashLock.Client.Configuration;

builder.Services.AddStashLock(cfg => cfg
    .WithBox("myapp", "prod")
    .WithCache(ttl: TimeSpan.FromHours(2))
);

// Inject anywhere
public class MyService(ISecretsStore secrets)
{
    public string GetDbPassword() => secrets["Database:Password"];
}

Environment Variables

Variable Purpose Fallback
STASHLOCK_VAULT_KEY Vault key string (box.tag.version.password) Used by .FromEnvironment()
STASHLOCK_PRIVATE_KEY Base64-encoded X25519 private key Used by .WithBox(), .FromEncryptedFile()
STASHLOCK_API_URL Vault API base URL Defaults to https://deneblabvault.azurewebsites.net/api/
STASHLOCK_API_KEY API authentication key (Bearer token) Optional

Error Handling

try
{
    var store = await StashLock.CreateClient()
        .FromEnvironment()
        .OpenAsync();
}
catch (VaultConfigurationException ex)
{
    // Missing or invalid configuration (env var, key format)
}
catch (VaultNotFoundException ex)
{
    // Vault entry not found on server
}
catch (DecryptionException ex)
{
    // Decryption failed — wrong password or key
}

Development Secrets File

Create a secrets.json in dev/secrets/ under your project root:

{
  "Database:ConnectionString": "Server=localhost;Database=dev",
  "Database:Password": "dev-password",
  "ExternalApi:Key": "dev-api-key"
}

FromDevFile() (without a path) auto-discovers this file when running in Dev or Test mode.

License

MIT License - see LICENSE file for details

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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
0.4.2 0 3/12/2026
0.3.122 0 3/12/2026
0.3.121 0 3/12/2026
0.3.119 0 3/12/2026
0.3.118 0 3/12/2026
0.3.117 0 3/12/2026
0.3.115 0 3/12/2026
0.3.112 4 3/12/2026
0.3.111 4 3/12/2026
0.3.110 4 3/12/2026
0.3.109 4 3/12/2026
0.3.108 31 3/11/2026
0.3.107 25 3/11/2026
0.3.106 27 3/11/2026
0.3.105 31 3/11/2026
0.3.103 24 3/11/2026
0.3.102 30 3/11/2026
0.3.100 32 3/11/2026
0.3.99 29 3/11/2026
0.3.98 30 3/11/2026
Loading failed