Tooark.Secrets
4.7.0
dotnet add package Tooark.Secrets --version 4.7.0
NuGet\Install-Package Tooark.Secrets -Version 4.7.0
<PackageReference Include="Tooark.Secrets" Version="4.7.0" />
<PackageVersion Include="Tooark.Secrets" Version="4.7.0" />
<PackageReference Include="Tooark.Secrets" />
paket add Tooark.Secrets --version 4.7.0
#r "nuget: Tooark.Secrets, 4.7.0"
#:package Tooark.Secrets@4.7.0
#addin nuget:?package=Tooark.Secrets&version=4.7.0
#tool nuget:?package=Tooark.Secrets&version=4.7.0
Tooark.Secrets
Library with the Tooark family's secrets and parameters abstractions. The store feeds IConfiguration, so the
packages that already read their options from configuration (Storage, Securities, OpenId, Observability) receive the
store's values without any change. For what is only known at runtime, there is the ISecretService, with cache.
The package has no cloud SDK: each store lives in its own package.
| Package | Secrets | Parameters | Store credential |
|---|---|---|---|
Tooark.Secrets.Aws |
AWS Secrets Manager | AWS Parameter Store | AWS default chain (role) |
Tooark.Secrets.Gcp |
Google Secret Manager | Google Parameter Manager | Application Default Credentials |
Tooark.Secrets.Vault |
Vault or OpenBao KV v2 | the same KV | Token, AppRole or Kubernetes |
π Languages: πΊπΈ English (this file) Β· π§π· PortuguΓͺs
π Contents
- Overview
- Installation
- Configuration
- From store names to keys
- Runtime reads
- Usage Examples
- Dependencies
- Best Practices
- Error Codes and Solutions
- Contributing
- Help & Security
- Support
- License
π Overview
- Configuration source β the store enters
IConfigurationlike any other source, and wins over the earlier ones (appsettings.json, environment variables).Storage:SecretKey,Jwt:SecretorOpenId:Entra:ClientSecretcome from the store, and theAddTooark*calls keep reading and validating the options as always. ISecretServiceβ reads a secret by name at runtime, such as a tenant's API key, with cache. It reads secrets only: parameters are configuration and come through the source.- Read at startup β the source reads the store once, when the configuration is built. Tooark packages validate
and keep their options at startup, so rotating a secret they use takes a restart or a new deploy. The
ISecretServicereads again when the cache expires. - The store credential comes from the environment β AWS role, Google Application Default Credentials, or
Kubernetes/AppRole auth in Vault. A store access key kept in
appsettings.jsonwould only move the secret around. - Fails at startup β an unreachable store, a missing permission or a timeout keeps the application from starting,
unless
Optional.
π§ Installation
Install the store package, which brings this one:
dotnet add package Tooark.Secrets.Aws
# or
dotnet add package Tooark.Secrets.Gcp
# or
dotnet add package Tooark.Secrets.Vault
The Tooark aggregator brings only this package, with the abstractions, and no provider.
βοΈ Configuration
appsettings.json
The options live in the Secrets section, together with the store's own
(AWS,
Google Cloud,
Vault):
{
"Secrets": {
"SecretsPrefix": "arkuest/prod",
"TimeoutSeconds": 30,
"CacheMinutes": 5
}
}
Program.cs
The source goes on the IConfigurationBuilder, after the other sources and before the AddTooark* calls that
read the options:
using Tooark.Secrets.Aws.Injections;
var builder = WebApplication.CreateBuilder(args);
// The store goes on top of appsettings.json and environment variables
builder.Configuration.AddTooarkSecretsAws();
// Storage, Securities and the others already receive the store's values
builder.Services.AddTooarkStorageAws(builder.Configuration);
// Optional: runtime reads, with cache
builder.Services.AddTooarkSecretsAws(builder.Configuration);
The source's options come from the Secrets section of the sources already added, and the code adjustment applies on
top: AddTooarkSecretsAws(options => options.SecretsPrefix = "arkuest/prod").
SecretsOptions properties
| Property | Type | Default | Description |
|---|---|---|---|
ExpandJson |
bool |
false |
A value that is a JSON object becomes child keys. See ExpandJson |
Optional |
bool |
false |
Ignores a failure to load the source, and the application starts without the store's keys |
TimeoutSeconds |
int |
30 |
Maximum time to load the source at startup |
CacheMinutes |
int |
5 |
How long a secret read by ISecretService stays cached. Zero turns the cache off |
π From store names to keys
Each secret or parameter under the configured prefix becomes a key. The name loses the prefix, and / and __
become ::
| Store | Prefix | Name in the store | Key |
|---|---|---|---|
| AWS Secrets Manager | arkuest/prod |
arkuest/prod/Jwt/Secret |
Jwt:Secret |
| AWS Parameter Store | /arkuest/prod |
/arkuest/prod/Storage/Bucket |
Storage:Bucket |
| Google Secret Manager | arkuest-prod |
arkuest-prod__OpenId__Entra__ClientSecret |
OpenId:Entra:ClientSecret |
| Vault/OpenBao (KV v2) | arkuest/prod |
field SecretKey of secret arkuest/prod/Storage |
Storage:SecretKey |
- The prefix respects the level boundary:
arkuest/proddoes not takearkuest/production. - Google does not accept
/or:in names, so levels there use__, as in environment variables. - In Vault, each field of a secret is a key, and the fields of the secret at the path itself sit at the root.
- With the same name in a secret and a parameter, the secret wins.
ExpandJson
Off, the default, the value stays as text, even when it is JSON. That fits one secret per key, including a Google
service account key in Storage:CredentialsJson.
On, a value that is a JSON object becomes child keys. That fits one document with many keys, such as the Secrets Manager "key/value" secret:
{ "Jwt": { "Secret": "..." }, "Storage__SecretKey": "...", "OpenId": { "Entra": { "ClientSecret": "..." } } }
Kept in the secret arkuest/prod, the prefix itself, it becomes Jwt:Secret, Storage:SecretKey and
OpenId:Entra:ClientSecret. Text inside the document is never parsed as JSON again, so a service account key kept
there as text stays whole. The expansion applies to every value of the source: with one secret per key, leave it
off.
What the Tooark packages read from the store
Any configuration key can come from the store. The family's sensitive ones:
| Package | Keys |
|---|---|
Tooark.Storage.Aws |
Storage:AccessKey, Storage:SecretKey, Storage:SessionToken |
Tooark.Storage.Gcp |
Storage:CredentialsJson |
Tooark.Securities |
Jwt:Secret, Jwt:PrivateKey, Cryptography:Secret, DataProtection:CertificatePassword |
Tooark.Securities.OpenId |
OpenId:{provider}:ClientSecret |
Tooark.Observability |
the OTLP Headers, with the collector key |
π Runtime reads
ISecretService reads a secret by its name in the store. The value stays cached for CacheMinutes; a missing secret
is not cached, so it is read as soon as it is created.
| Method | Returns | Description |
|---|---|---|
GetAsync(name) |
string? |
Current value of the secret, or null when it does not exist |
GetFieldAsync(name, field) |
string? |
Field of a JSON secret, exact case; null when the secret or the field is missing |
In Vault, the value is the JSON object with the secret's fields, and GetFieldAsync reads one of them. Parameters do
not go through the service: they are configuration.
using Tooark.Secrets.Interfaces;
public sealed class TenantService(ISecretService secrets)
{
public Task<string?> ApiKey(string tenant, CancellationToken cancellationToken) =>
secrets.GetFieldAsync($"arkuest/tenants/{tenant}", "ApiKey", cancellationToken);
}
π Usage Examples
One document with every key (AWS)
{ "Secrets": { "SecretsPrefix": "arkuest/prod", "ExpandJson": true } }
The secret arkuest/prod holds the JSON document, and each field becomes a key.
One secret per key (Google Cloud)
{ "Secrets": { "ProjectId": "arkuest", "SecretsPrefix": "arkuest-prod" } }
The secrets arkuest-prod__Jwt__Secret and arkuest-prod__Storage__CredentialsJson become Jwt:Secret and
Storage:CredentialsJson.
Optional source in development
builder.Configuration.AddTooarkSecretsVault(options => options.Optional = builder.Environment.IsDevelopment());
π Dependencies
| Package | Version | Description |
|---|---|---|
Tooark.Exceptions |
4.x | Exceptions (InternalServerErrorException) |
Microsoft.Extensions.Options.ConfigurationExtensions |
8.x/10.x | Configuration abstractions and binder |
The package runs on the base .NET runtime, without ASP.NET Core and without any cloud SDK.
π― Best Practices
- Nothing sensitive in
appsettings.jsonβ with the store, the versioned file keeps only what is not secret: region, bucket, prefix. - Environment identity for the store β role, service account or Kubernetes auth; the store credential cannot come from the store.
- One prefix per environment β
arkuest/prod,arkuest/staging: the application's permission stays scoped to its own. - Rotation with a restart β Tooark packages read their options at startup; change the secret and deploy again or restart the instances.
Optionalonly where it makes sense β in production, starting without the secrets is usually worse than not starting.
β οΈ Error Codes and Solutions
| Message | Exception | Description | Solution |
|---|---|---|---|
Secrets.LoadFailed;{store} |
InternalServerErrorException |
The source did not load: access, network or timeout | See the InnerException; check the identity and network |
Secrets.NameRequired |
BadRequestException |
Blank secret name | Provide the name |
Secrets.FieldRequired |
BadRequestException |
Blank field in GetFieldAsync |
Provide the field |
Secrets.NotJsonObject;{name} |
InternalServerErrorException |
GetFieldAsync on a secret that is not a JSON object |
Use GetAsync, or keep the secret as an object |
Secrets.AccessDenied |
InternalServerErrorException |
The identity cannot read the secret | Grant the read permission |
Secrets.OperationFailed |
InternalServerErrorException |
Store or network failure | See the InnerException |
Options.Secrets.TimeoutInvalid |
InternalServerErrorException |
TimeoutSeconds below 1 |
Use at least 1 second |
Options.Secrets.CacheMinutesInvalid |
InternalServerErrorException |
Negative CacheMinutes |
Use zero or more |
Options.Secrets.SourceNotConfigured |
InternalServerErrorException |
Configuration source without a prefix or path | Provide the store prefix or path |
Each store's own errors are in its README.
π€ Contributing
Contributions are welcome! Start with CONTRIBUTING.md β it covers the development workflow, the coding and commit conventions and the pull request checklist. Bugs and feature requests go through the issue templates of the Tooark repository.
By participating you agree to the Code of Conduct.
π Help & Security
- β Questions, bugs, feature ideas β see SUPPORT.md for the right channel
- π Security vulnerabilities β do not open a public issue; follow SECURITY.md
π Support
If Tooark helps your projects, consider supporting its development:
- π GitHub Sponsors
- β Ko-fi
Every contribution helps keep the project maintained and improving. Thank you! π
π License
This project is licensed under the BSD 3-Clause License.
| Product | Versions 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 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. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Options (>= 10.0.12)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.12)
- Tooark.Exceptions (>= 4.7.0)
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- Tooark.Exceptions (>= 4.7.0)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Tooark.Secrets:
| Package | Downloads |
|---|---|
|
Tooark
Package with all Tooark resources for .NET applications. |
|
|
Tooark.Secrets.Vault
Package that loads the KV v2 secrets of HashiCorp Vault or OpenBao into IConfiguration and implements the Tooark ISecretService on them, with token, AppRole or Kubernetes authentication. |
|
|
Tooark.Secrets.Gcp
Package that loads Google Cloud Secret Manager secrets and Parameter Manager parameters into IConfiguration and implements the Tooark ISecretService on Secret Manager. |
|
|
Tooark.Secrets.Aws
Package that loads AWS Secrets Manager secrets and Systems Manager Parameter Store parameters into IConfiguration and implements the Tooark ISecretService on Secrets Manager. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.7.0 | 154 | 9/30/2026 |