# OS Keychain
Store secrets in your operating system's native secure storage.
## Supported Platforms
- **macOS:** Keychain Access (built-in)
- **Windows:** Credential Manager (built-in)
- **Linux:** Secret Service (via libsecret - GNOME Keyring, KWallet)
## Quick Start
```bash
# 1. Linux only: Install libsecret
sudo apt-get install libsecret-1-0 libsecret-1-dev # Ubuntu/Debian
# 2. Configure provider
cat >> fnox.toml << 'EOF'
[providers]
keychain = { type = "keychain", service = "fnox" }
EOF
# 3. Store a secret in OS keychain
fnox set DATABASE_URL "postgresql://localhost/mydb" --provider keychain
# 4. Retrieve from keychain
fnox get DATABASE_URL
```
## Linux Setup
On Linux, you need libsecret installed:
::: code-group
```bash [Ubuntu/Debian]
sudo apt-get install libsecret-1-0 libsecret-1-dev
```
```bash [Fedora/RHEL]
sudo dnf install libsecret libsecret-devel
```
```bash [Arch]
sudo pacman -S libsecret
```
:::
macOS and Windows have built-in support—no installation needed.
## Configuration
```toml
[providers]
keychain = { type = "keychain", service = "fnox", prefix = "myapp/" } # Prefix is optional
```
### Service Name
The `service` acts as a namespace to isolate fnox secrets from other applications:
```toml
[providers]
keychain = { service = "fnox" } # All fnox secrets under "fnox" service
# Or use project-specific service
keychain = { service = "myapp" } # All secrets under "myapp" service
```
### Prefix
Optional prefix prepended to secret names:
```toml
[providers]
keychain = { service = "fnox", prefix = "myapp/" } # "database-url" becomes "myapp/database-url"
```
## How It Works
1. **Storage:** Secrets are stored in the OS credential manager (encrypted by OS)
2. **Config:** `fnox.toml` contains only the secret name, not the value
3. **Retrieval:** fnox queries the OS keychain API
4. **Service:** Acts as a namespace (isolates fnox secrets from other apps)
5. **Prefix:** Additional namespacing within the service
## Usage
### Store a Secret
```bash
fnox set DATABASE_URL "postgresql://localhost/mydb" --provider keychain
```
Your `fnox.toml`:
```toml
[secrets]
DATABASE_URL = { provider = "keychain", value = "database-url" } # ← Keychain entry name, not the actual secret
```
The actual secret is stored in the OS keychain, encrypted.
### Retrieve a Secret
```bash
fnox get DATABASE_URL
```
### Run Commands
```bash
fnox exec -- npm run dev
```
## Recommended: Use With Age, Not As Bulk Storage
The OS keychain is designed for **a few** long-lived secrets, not as the storage backend for every secret in a project. On macOS in particular, the system pops a Security dialog the first time each application accesses each keychain item — so if you store ten secrets directly in the keychain, you'll get up to ten "Always Allow / Allow / Deny" prompts the first time `fnox exec` runs.
The pattern that scales much better is to store a single **age private key** in the keychain and encrypt all your secrets with age:
```toml
[providers]
keychain = { type = "keychain", service = "fnox" }
age = { type = "age", recipients = ["age1..."], identity = { provider = "keychain", value = "age-key" } }
[secrets]
# Many secrets, all encrypted with age — only one keychain access (the age key)
DATABASE_URL = { provider = "age", value = "encrypted..." }
API_KEY = { provider = "age", value = "encrypted..." }
STRIPE_KEY = { provider = "age", value = "encrypted..." }
# ...
```
This way:
- **One keychain item, one dialog.** Hitting "Always Allow" once authorizes the age key for that machine.
- Adding more secrets is free — they go into the encrypted config, not into the keychain.
- Loss of the keychain item is recoverable from any other machine that holds the same age identity.
Reach for direct `provider = "keychain"` only for the handful of bootstrap secrets that don't have anything else to decrypt them (e.g., the age key itself, an OP service account token).
## Bootstrap Pattern
A common pattern is to store provider tokens in the keychain:
```toml
[providers]
keychain = { type = "keychain", service = "fnox" }
age = { type = "age", recipients = ["age1..."] }
[secrets]
OP_SERVICE_ACCOUNT_TOKEN = { provider = "keychain", value = "op-token" } # Store 1Password token in keychain
DATABASE_URL = { provider = "age", value = "encrypted..." } # Other secrets encrypted with age
```
Then bootstrap:
```bash
export OP_SERVICE_ACCOUNT_TOKEN=$(fnox get OP_SERVICE_ACCOUNT_TOKEN)
# Now can access 1Password secrets
fnox exec -- ./start.sh
```
## Example Configurations
### Personal Project
```toml
[providers]
keychain = { type = "keychain", service = "myapp" }
[secrets]
DATABASE_URL = { provider = "keychain", value = "database-url" }
API_KEY = { provider = "keychain", value = "api-key" }
```
### Bootstrap Tokens
```toml
[providers]
keychain = { type = "keychain", service = "fnox-tokens" }
[secrets]
GITHUB_TOKEN = { provider = "keychain", value = "github" }
NPM_TOKEN = { provider = "keychain", value = "npm" }
```
### Machine-Specific Secrets
```toml
# fnox.local.toml (gitignored)
[providers]
keychain = { type = "keychain", service = "fnox-local" }
[secrets]
LAPTOP_DB_URL = { provider = "keychain", value = "laptop-db" }
```
## Platform Details
### macOS Keychain
Secrets stored in:
- **Login Keychain** (default)
- **System Keychain** (requires admin)
View in Keychain Access app:
1. Open Keychain Access
2. Search for service name (e.g., "fnox")
3. Double-click to view/edit
### Windows Credential Manager
Secrets stored in Windows Credential Manager.
View in Control Panel:
1. Control Panel → User Accounts → Credential Manager
2. Windows Credentials
3. Look for fnox entries
### Linux Secret Service
Secrets stored in:
- **GNOME Keyring** (GNOME desktop)
- **KWallet** (KDE desktop)
- **Other Secret Service implementations**
View with Seahorse (GNOME):
```bash
sudo apt install seahorse
seahorse
```
## Pros
- ✅ OS-managed encryption
- ✅ Cross-platform (macOS, Windows, Linux)
- ✅ No external dependencies
- ✅ Free
- ✅ Built into operating system
- ✅ Secure by default
## Cons
- ❌ Requires GUI/interactive session (doesn't work in headless CI)
- ❌ Not suitable for teams (secrets are per-machine)
- ❌ Keyring must be unlocked
- ❌ No audit logs
- ❌ No centralized management
## Limitations
### Headless Environments
Keychain provider requires a GUI session and doesn't work in:
- CI/CD (GitHub Actions, GitLab CI, etc.)
- Docker containers (without X11/Wayland)
- SSH sessions (without forwarding)
- Headless servers
For CI/CD, use age encryption or cloud providers instead.
### Tests Auto-Skip in CI
fnox's keychain tests automatically skip in CI environments:
```bash
# Runs locally
mise run test:bats
# Skips keychain tests in CI
# GitHub Actions, GitLab CI, etc.
```
## Security
- **Encryption:** OS handles encryption (typically AES-256)
- **Access control:** OS enforces access (user/session isolation)
- **Keyring unlock:** May require password entry on first access
- **Memory protection:** OS manages secure memory handling
## Troubleshooting
### "Keyring is locked"
Unlock your keyring:
**macOS:**
- Keyring unlocks automatically on login
**Linux (GNOME):**
```bash
# Unlock manually
gnome-keyring-daemon --unlock
```
**Windows:**
- Credential Manager unlocks on login
### "Access denied"
Check that the process has access:
- **macOS:** May prompt for Keychain Access permission
- **Linux:** Ensure Secret Service is running
- **Windows:** Check User Account Control settings
### "Service not available" (Linux)
Install and start Secret Service:
```bash
# Ubuntu/Debian
sudo apt-get install gnome-keyring
gnome-keyring-daemon --start
# Or use KWallet
sudo apt-get install kwalletmanager
```
## Best Practices
1. **Use for local development only** - Not for teams or CI
2. **Bootstrap provider tokens** - Store 1Password/AWS tokens
3. **Machine-specific overrides** - Use in `fnox.local.toml`
4. **Descriptive service names** - Use project-specific services
5. **Keep keyring unlocked** - Unlock on login for convenience
## Next Steps
- [Age Encryption](/providers/age) - Team-friendly alternative
- [Hierarchical Config](/guide/hierarchical-config) - Per-machine configuration with fnox.local.toml
- [1Password](/providers/1password) - Team password manager