Documentation
Everything you need to install, configure, and use Dev Secret Stash.
Install the CLI
DevSecretStash is distributed as a .NET global tool. You need the .NET SDK 9.0+ installed.
dotnet tool install --global DevSecretStash
If dss is not found after install, add the dotnet tools directory to your PATH:
# Linux / macOS — add to ~/.bashrc or ~/.zshrc for persistence
export PATH="$PATH:$HOME/.dotnet/tools"
# Windows PowerShell — usually added automatically, but if not:
$env:PATH += ";$env:USERPROFILE\.dotnet\tools"
Verify the installation:
dss --help
To update to the latest version:
dotnet tool update --global DevSecretStash
Quick Start
1. Create an account
Register via the CLI (encryption keys are generated locally on your machine):
dss register
Or create an account on the website and then log in via the CLI:
dss login
2. Set up secrets for your project
If your project doesn't have user secrets initialized yet:
# Initialize secrets (adds UserSecretsId to .csproj)
cd /path/to/your/project
dotnet user-secrets init
# Add secrets
dotnet user-secrets set "ConnectionStrings:Default" "Server=mydb;Password=secret123"
dotnet user-secrets set "ApiKey" "sk_live_abc123"
dotnet user-secrets set "Smtp:Password" "email-pw"
# View your secrets
dotnet user-secrets list
3. Push secrets
From a .NET project directory that has a UserSecretsId in its .csproj:
dss push
Or specify the ID explicitly:
dss push my-project-secrets-id
4. Pull on another machine
dss login
dss pull
That's it. Your secrets are now synced. Run dotnet user-secrets list to confirm.
Working with .NET User Secrets
DevSecretStash syncs the secrets managed by dotnet user-secrets. Here's how they work together.
Setting individual secrets
dotnet user-secrets set "ConnectionStrings:Default" "Server=prod;Password=s3cret"
dotnet user-secrets set "Jwt:SigningKey" "my-long-secret-key"
dotnet user-secrets set "SendGrid:ApiKey" "SG.xxxxxxxx"
# Then sync
dss push
Sharing secrets across projects
dotnet user-secrets is project-specific — each collection is tied to a UserSecretsId in the .csproj. But you can reuse the same ID across multiple projects to share secrets:
<!-- In each .csproj that should share secrets -->
<PropertyGroup>
<UserSecretsId>my-shared-secrets</UserSecretsId>
</PropertyGroup>
Managing secrets directly with dss
The dss secrets commands let you create and manage secret collections without dotnet user-secrets or a .csproj file:
# Create a new collection
dss secrets init my-app-secrets
# Add secrets
dss secrets set my-app-secrets "ConnectionStrings:Default" "Server=mydb;Password=s3cret"
dss secrets set my-app-secrets "ApiKey" "sk_live_abc123"
# View secrets
dss secrets list my-app-secrets
# Remove a secret
dss secrets remove my-app-secrets "ApiKey"
# Clear all secrets
dss secrets clear my-app-secrets
# Link a .csproj to use this collection
dss secrets link my-app-secrets
dss secrets link my-app-secrets --project ./src/MyApp/MyApp.csproj
# Sync to all your machines
dss push my-app-secrets
Secrets management commands
| Command | Description |
|---|---|
dss secrets init <id> | Create a new empty secrets collection |
dss secrets set <id> <key> <value> | Set a secret (creates collection if needed) |
dss secrets remove <id> <key> | Remove a secret |
dss secrets list [id] | List all secrets (auto-detects from .csproj if omitted) |
dss secrets clear <id> | Remove all secrets from a collection |
dss secrets link <id> [-p project] | Set a .csproj's UserSecretsId to this collection |
Where secrets are stored locally
| Platform | Path |
|---|---|
| Windows | %APPDATA%\Microsoft\UserSecrets\<UserSecretsId>\secrets.json |
| Linux / macOS | ~/.microsoft/usersecrets/<UserSecretsId>/secrets.json |
How It Works
[Your Machine] [devsecretstash.com] [Another Machine]
secrets.json --> encrypt --> encrypted blob (SQLite) --> decrypt --> secrets.json
(AES-256-GCM) (AES-256-GCM)
- AES-256-GCM encrypts your secrets using a random master key
- Argon2id derives a key-encryption-key from your password to wrap the master key
- The server only stores encrypted blobs — it cannot read your secrets
- Password changes re-wrap the master key without re-encrypting all secrets
CLI Commands
| Command | Description |
|---|---|
dss config --server-url <url> | Set or view the server URL |
dss register | Create a new account (generates encryption keys locally) |
dss login | Authenticate and cache credentials locally |
dss logout | Clear cached credentials from this machine |
dss push [id] | Encrypt and upload local secrets |
dss pull [id] | Download and decrypt secrets to local machine |
dss status [id] | Compare local vs remote sync status |
dss list | List all secret collections stored on the server |
Global options: --verbose / -v enables detailed HTTP request/response logging.
If [id] is omitted, the CLI auto-detects UserSecretsId from a .csproj in the current directory.
The CLI defaults to https://devsecretstash.com. Use dss config to point at a self-hosted instance.
Security Model
DevSecretStash uses a two-layer encryption scheme. Your plaintext secrets never leave your machine.
Encryption flow
Your password
| Argon2id (64MB memory, 3 iterations)
v
Key-Encryption-Key (KEK) — never sent to server
| AES-256-GCM
v
Wraps your Master Encryption Key (MEK) — server stores wrapped version only
|
v
MEK encrypts all your secrets via AES-256-GCM
| Layer | Mechanism | Purpose |
|---|---|---|
| Authentication | Argon2id (server-side) | Verify your identity |
| Key wrapping | Argon2id (client) + AES-256-GCM | Protect master key with password |
| Secret encryption | AES-256-GCM | Encrypt secrets before upload |
| Transport | HTTPS + HSTS | Protect data in transit |
| Local storage | chmod 600 (Linux/Mac) | Protect cached keys on disk |
| API auth | JWT (15m) + refresh tokens (30d) | Stateless auth with rotation |
| Rate limiting | 10 attempts / 15 min | Prevent brute force |
What a server compromise reveals
An attacker with full database access gets: your email, a password hash (Argon2id), an encrypted master key, and encrypted secret blobs. They would need to brute-force your password through Argon2id to decrypt anything. No plaintext secrets are ever on the server — not in memory, not in logs, not in the database.
API Reference
The full REST API is documented via Swagger at /swagger.
| Endpoint | Auth | Description |
|---|---|---|
POST /api/auth/register | No | Create account + store wrapped master key |
POST /api/auth/login | No | Authenticate, get JWT + encrypted master key |
POST /api/auth/refresh | No | Rotate refresh token, get new JWT |
POST /api/auth/change-password | JWT | Update password + re-wrapped master key |
GET /api/secrets | JWT | List all collections |
GET /api/secrets/{id} | JWT | Get encrypted collection |
PUT /api/secrets/{id} | JWT | Push encrypted collection (optimistic concurrency via version) |
DELETE /api/secrets/{id} | JWT | Delete collection |
Self-Hosting
You can self-host DevSecretStash instead of using devsecretstash.com.
Docker
docker build -t devsecretstash-api -f src/DevSecretStash.Api/Dockerfile .
docker run -d -p 8080:8080 \
-v dss-data:/app/data \
-e Jwt__Key="your-secret-key-minimum-32-characters!" \
devsecretstash-api
Azure App Service
# Create resource group and B1 Linux plan
az group create --name devsecretstash-rg --location centralus
az appservice plan create --name devsecretstash-plan \
--resource-group devsecretstash-rg --is-linux --sku B1
# Create web app
az webapp create --name devsecretstash \
--resource-group devsecretstash-rg \
--plan devsecretstash-plan --runtime "DOTNETCORE:9.0"
# Configure
az webapp config appsettings set --name devsecretstash \
--resource-group devsecretstash-rg --settings \
Jwt__Key="YOUR-SECRET-KEY-MIN-32-CHARS" \
ConnectionStrings__Default="Data Source=/home/site/data/devsecretstash.db" \
ASPNETCORE_URLS="http://+:8080"
# Deploy
dotnet publish src/DevSecretStash.Api -c Release -o ./publish
cd publish && zip -r ../deploy.zip . && cd ..
az webapp deploy --name devsecretstash \
--resource-group devsecretstash-rg --src-path deploy.zip --type zip
Point CLI at your server
dss config --server-url https://your-server.example.com
Server configuration
| Setting | Environment Variable | Default |
|---|---|---|
| Database | ConnectionStrings__Default | Data Source=devsecretstash.db |
| JWT Key | Jwt__Key | Change in production! |
| JWT Issuer | Jwt__Issuer | DevSecretStash |
| Token lifetime | Jwt__AccessTokenMinutes | 15 |
| Refresh lifetime | Jwt__RefreshTokenDays | 30 |