Bitwarden
Integrate with Bitwarden (or self-hosted Vaultwarden) to retrieve secrets from your vault.
Quick Start
# 1. Install Bitwarden CLI (auto-installed via mise)
# Already available!
# 2. Login to Bitwarden
bw login
# 3. Unlock and get session token
export BW_SESSION=$(bw unlock --raw)
# 4. Store session token (optional, for bootstrap)
fnox set BW_SESSION "$(bw unlock --raw)" --provider age
# 5. Configure Bitwarden provider
cat >> fnox.toml << 'EOF'
[providers.bitwarden]
type = "bitwarden"
EOF
# 6. Add secrets to Bitwarden
bw create item --name "Database" \
--username "admin" \
--password "secret-password"
# 7. Reference in fnox
cat >> fnox.toml << 'EOF'
[secrets.DATABASE_PASSWORD]
provider = "bitwarden"
value = "Database"
EOF
# 8. Use it
fnox get DATABASE_PASSWORDPrerequisites
- Bitwarden account (or self-hosted Vaultwarden)
- Bitwarden CLI (automatically installed via mise)
Installation
The Bitwarden CLI is installed automatically when using fnox via mise. Manual installation:
# macOS
brew install bitwarden-cli
# Linux
npm install -g @bitwarden/cli
# Windows
choco install bitwarden-cliSetup
1. Login to Bitwarden
# Cloud Bitwarden
bw login
# Self-hosted Vaultwarden
bw config server https://vault.example.com
bw login2. Unlock and Get Session Token
# Unlock vault
export BW_SESSION=$(bw unlock --raw)
# Or if already unlocked
bw unlock
# Copy the session token from output3. Store Session Token (Bootstrap)
Optionally, store the session encrypted for easy bootstrap:
# Store token encrypted with age
fnox set BW_SESSION "$(bw unlock --raw)" --provider age
# Next time, bootstrap from fnox:
export BW_SESSION=$(fnox get BW_SESSION)4. Configure Bitwarden Provider
[providers.bitwarden]
type = "bitwarden"
collection = "my-collection-id" # Optional
organization_id = "my-org-id" # OptionalAdding Secrets to Bitwarden
Via Bitwarden Web Vault
- Go to vault.bitwarden.com
- Click + Add Item
- Choose type (Login, Card, Identity, Secure Note)
- Fill in details
- Save
Via Bitwarden CLI
# Unlock first
export BW_SESSION=$(bw unlock --raw)
# Create a login item
bw create item \
--name "Database" \
--username "admin" \
--password "secret-password" \
--url "https://db.example.com"
# Create with JSON
echo '{
"type": 1,
"name": "API Key",
"login": {
"password": "sk_live_abc123xyz789"
}
}' | bw encode | bw create item
# List items
bw list itemsReferencing Secrets
Add references to fnox.toml:
[secrets.DATABASE_PASSWORD]
provider = "bitwarden"
value = "Database" # Item name (fetches 'password' field)
[secrets.DB_USERNAME]
provider = "bitwarden"
value = "Database/username" # Specific field
[secrets.API_KEY]
provider = "bitwarden"
value = "API Key"Reference Formats
1. Item Name (Gets Password Field)
[secrets.MY_SECRET]
provider = "bitwarden"
value = "My Item" # → Gets the 'password' field2. Item Name + Field
[secrets.USERNAME]
provider = "bitwarden"
value = "Database/username"
[secrets.PASSWORD]
provider = "bitwarden"
value = "Database/password"
[secrets.TOTP]
provider = "bitwarden"
value = "Database/totp"Supported fields: username, password, notes, uri, totp
Custom Fields
Custom field extraction is not yet implemented. Use standard fields for now.
Usage
# Unlock Bitwarden (once per session)
export BW_SESSION=$(bw unlock --raw)
# Or bootstrap: export BW_SESSION=$(fnox get BW_SESSION)
# Get secrets
fnox get DATABASE_PASSWORD
# Run commands
fnox exec -- npm startMulti-Environment Example
# Bootstrap session token (encrypted in git)
[providers.age]
type = "age"
recipients = ["age1..."]
[secrets.BW_SESSION]
provider = "age"
value = "encrypted-session..."
# Development: Bitwarden
[providers.bitwarden]
type = "bitwarden"
[secrets.DATABASE_URL]
provider = "bitwarden"
value = "Dev Database"
# Production: Different Bitwarden organization
[profiles.production.providers.bitwarden]
type = "bitwarden"
organization_id = "prod-org-id"
[profiles.production.secrets.DATABASE_URL]
provider = "bitwarden"
value = "Prod Database"Self-Hosted Vaultwarden
Vaultwarden is a lightweight, open-source Bitwarden-compatible server:
# Configure Bitwarden CLI to use Vaultwarden
bw config server https://vault.example.com
# Login
bw login
# Unlock
export BW_SESSION=$(bw unlock --raw)
# Use normally with fnox
fnox get DATABASE_PASSWORDCI/CD Example
GitHub Actions
name: Test
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jdx/mise-action@v3
- name: Setup Bitwarden session
env:
FNOX_AGE_KEY: ${{ secrets.FNOX_AGE_KEY }}
run: |
# Bootstrap session from fnox (if stored)
export BW_SESSION=$(fnox get BW_SESSION)
- name: Run tests
env:
BW_SESSION: ${{ secrets.BW_SESSION }} # Or set directly from GitHub Secrets
run: |
fnox exec -- npm testSession Token Management
The BW_SESSION token expires after a period of inactivity.
Option 1: Unlock Each Time
#!/bin/bash
export BW_SESSION=$(bw unlock --raw)
fnox exec -- npm startOption 2: Store Encrypted (Bootstrap)
# Store once
fnox set BW_SESSION "$(bw unlock --raw)" --provider age
# Use repeatedly
export BW_SESSION=$(fnox get BW_SESSION)
fnox exec -- npm startToken Expiration
Bitwarden session tokens expire. You'll need to unlock periodically:
export BW_SESSION=$(bw unlock --raw)Collections and Organizations
Filter secrets by collection or organization:
[providers.bitwarden]
type = "bitwarden"
collection = "abc123-collection-id"
organization_id = "org-id"Get collection ID:
bw list collections | jq '.[] | {name, id}'Get organization ID:
bw list organizations | jq '.[] | {name, id}'Testing with Vaultwarden
For local development without a Bitwarden account:
# Start local vaultwarden server
source ./test/setup-bitwarden-test.sh
# Follow on-screen instructions:
# 1. Create account at http://localhost:8080
# 2. Login: bw login
# 3. Unlock: export BW_SESSION=$(bw unlock --raw)
# Run tests
mise run test:bats -- test/bitwarden.batsSee test/BITWARDEN_TESTING.md for details.
Pros
- ✅ Open source
- ✅ Free for personal use
- ✅ Self-hosting option (Vaultwarden)
- ✅ Good audit logs
- ✅ Cross-platform
Cons
- ❌ UI less polished than 1Password
- ❌ Session token expires (need to unlock regularly)
- ❌ Requires network access (unless self-hosted locally)
Troubleshooting
"You are not logged in"
bw login"Vault is locked"
export BW_SESSION=$(bw unlock --raw)"Item not found"
Check the item exists:
bw list items | jq '.[] | {name, id}'"Session token expired"
Re-unlock:
export BW_SESSION=$(bw unlock --raw)Best Practices
- Store session token encrypted - Use age to encrypt
BW_SESSION - Use collections for organization - Group secrets logically
- Self-host for full control - Consider Vaultwarden
- Unlock before long operations - Session won't expire mid-operation
- Use organizations for teams - Better access control
Next Steps
- 1Password - Commercial alternative
- OS Keychain - Local alternative
- Real-World Example - Complete setup