Skip to main content

Secure API key and token koffer with session-based unlock

Project description

koffer

koffer >_

A CLI tool for managing API keys and tokens. Instead of scattering .env files across your projects, store your secrets in one encrypted file and inject them into your shell right before you need them.

Keys are AES-256-GCM encrypted with Argon2id key derivation, decrypted only when you run koffer unlock.

Why "koffer"?

"Koffer" is a versatile Dutch word for trunk, briefcase or suitcase; a strangely suitable name for this project.

Koffer is designed to be an easy-to-install, portable, no-subscription keystore that works across Windows, Linux (WSL2), PowerShell, and Bash. It keeps your secrets (somewhat) organized and locked away from casual prying eyes. It is not a vault however, and it doesn't pretend to be. It's just a simple container for your API keys and other CLI secrets so they don't get lost in translation or left out in half a dozen .env files. Think of it as "carry-on" security for your development workflow.

Features

  • 🔐 Strong encryption: AES-256-GCM with Argon2id key derivation
  • 🔑 System keyring integration: Optional password storage in OS credential manager
  • 🐚 Shell integration: Works with PowerShell, Bash, and Zsh
  • 📦 Zero config: Sensible defaults for 40+ popular services
  • 💾 Portable: Single encrypted file, easy to backup/restore

Installation

Using uv

# Install as a tool (globally) using uv:
uv tool install koffer
# Install the latest (unreleased) development version:
uv tool install git+https://github.com/jsnel/koffer.git

Quick Start

# Add your first secret
koffer add openai
# Enter master password (first time creates the koffer)
# Enter your API key when prompted

# Recommended: run commands with secrets injected (secrets never printed)
koffer run -- python -c "import os; print('OPENAI_API_KEY' in os.environ)"

# If you really need env vars in the current shell:
# PowerShell:
Invoke-Expression (koffer unlock)

# Bash/Zsh:
eval "$(koffer unlock)"

Usage

Add secrets

# Known services get sensible defaults
koffer add openai          # -> OPENAI_API_KEY
koffer add anthropic       # -> ANTHROPIC_API_KEY
koffer add github          # -> GITHUB_TOKEN

# Custom env var or type
koffer add myservice --env-var MY_SECRET --type secret

Unlock (inject into current shell)

unlock is meant for convenience when tools insist on reading env vars from the current shell. For day-to-day usage, prefer koffer run -- <command> so secrets never need to be printed.

PowerShell:

Invoke-Expression (koffer unlock)
# or (equivalent)
koffer unlock | iex

Bash / Zsh / WSL:

eval "$(koffer unlock)"

Unlock specific secrets only:

eval "$(koffer unlock openai anthropic)"

💡 Tip: Your master password is automatically stored in your system's credential manager (Windows Credential Manager, macOS Keychain, or Linux Secret Service) after first use. Use --no-keyring to disable this.

By default, unlock base64-wraps its payload and prefers using the clipboard to reduce accidental exposure. If you want to inspect the generated commands, use:

# Print unlock payload to stdout (still base64-wrapped)
koffer unlock --stdout

# Print commands directly (masked, but decodable)
koffer unlock --stdout --no-obfuscate

# Show plaintext secrets (least secure)
koffer unlock --show-keys

Other commands

koffer list              # Show stored secrets
koffer remove <name>     # Delete a secret
koffer rotate            # Change master password
koffer export backup.enc # Backup koffer
koffer import backup.enc # Restore koffer
koffer run -- <command>  # Run a command with secrets injected (recommended)
koffer store-keyring     # Re-store password in credential manager
koffer purge-keyring     # Remove password from credential manager

Shell Profile Integration

Add to your shell profile for automatic unlocking:

PowerShell ($PROFILE):

# Unlock API keys on shell start (optional)
if (Get-Command koffer -ErrorAction SilentlyContinue) {
    Invoke-Expression (koffer unlock 2>$null)
}

Bash/Zsh (~/.bashrc or ~/.zshrc):

# Unlock API keys on shell start (optional)
command -v koffer &>/dev/null && eval "$(koffer unlock 2>/dev/null)"

WSL2 Integration

To share the same koffer between Windows and WSL2, create a symlink to your Windows koffer file:

cd ~
ln -s /mnt/c/Users/<username>/.koffer.enc .koffer.enc

Now both environments use the same encrypted secrets.

Security Model

Aspect Implementation
Encryption AES-256-GCM with 12-byte random nonce per secret
Key derivation Argon2id (64 MB memory, 3 iterations, 4 parallelism)
Storage ~/.koffer.enc with 600 permissions (Unix)
Credential storage Optional OS keyring (Windows Credential Manager, macOS Keychain, Linux Secret Service)

How it works

  1. Your master password derives an encryption key using Argon2id
  2. Each secret is encrypted with AES-256-GCM using a unique nonce
  3. The unlock command outputs shell export commands
  4. You eval the output to set environment variables in your current shell
  5. Environment variables are process-local and inherited only by child processes

What this protects against

  • ✅ Secrets at rest (encrypted on disk)
  • ✅ Casual shoulder surfing (secrets are masked in output)
  • ✅ Other users on shared systems (file permissions)

What this does NOT protect against

  • ❌ Malware with access to your shell's memory
  • ❌ Root/admin users on the same machine
  • ❌ Keyloggers capturing your master password

Remember: This is a koffer, not a vault. It's designed for convenience and "good enough" security for development workflows, not for high-stakes production secrets.

Supported Services

Supported is a big word here, but koffer includes default environment variable mappings for some number of services (and you can easily add your own):

AI/ML: OpenAI, Anthropic, Google/Gemini, Groq, Mistral, Cohere, Together, Perplexity, Fireworks, DeepSeek, xAI, HuggingFace, Replicate

DevOps: GitHub, GitLab, Vercel, Netlify, Railway, Fly.io, Render, Ngrok

Cloud: AWS, DigitalOcean, Linode, Vultr

Communication: Discord, Slack, Telegram, Twilio

Other: Stripe, SendGrid, Sentry, and more...

Unknown services default to SERVICENAME_API_KEY (or _TOKEN/_SECRET based on --type).

Development

# Clone the repository
git clone https://github.com/jsnel/koffer.git
cd koffer

# Setup env with dev dependencies
uv sync --extra dev

# Install git hooks (runs Ruff + basic hygiene checks)
uv run pre-commit install

# Run hooks against all files
uv run pre-commit run -a

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov

License

MIT License - see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

koffer-0.1.1.tar.gz (76.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

koffer-0.1.1-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file koffer-0.1.1.tar.gz.

File metadata

  • Download URL: koffer-0.1.1.tar.gz
  • Upload date:
  • Size: 76.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for koffer-0.1.1.tar.gz
Algorithm Hash digest
SHA256 e440e4ad0bd033d0d6eba39a7f3f32e1d317caf56653ca7421db308485ad7656
MD5 b4c124d3e1d675edb59e4c80fe089b69
BLAKE2b-256 ba6c085381c26f0e31689816de921bf867f76dee514c9f8c08631311594365c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for koffer-0.1.1.tar.gz:

Publisher: publish.yml on jsnel/koffer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file koffer-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: koffer-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 17.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for koffer-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3d6ee1bede0142818f3335cf57dabbc9e82b94d6952ab44c9e56ae6afd0056ca
MD5 6e47bcdadc3df488a51fafe9c16f2a20
BLAKE2b-256 a7bb0737ace913061f86b4b7a7971dae8d66b6c5137f2a383b6ed39d0e0fe1bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for koffer-0.1.1-py3-none-any.whl:

Publisher: publish.yml on jsnel/koffer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page