Password Manager — Mac + Windows Unified Setup with CLI Automation
Set up 1Password / Bitwarden on both machines, with SSH · Git · dotfiles auto-fetch integration.
A password manager pays back at two boundaries — (1) browser auto-fill, (2) automated secret fetch from terminal / dotfiles / CI. Using only (1) is half-utilization. Set up (2) and you stop writing plaintext secrets to .env, and a new machine bootstraps with one command.
This guide compares 1Password (recommended) · Bitwarden, then walks through unified Mac + Windows setup.
TL;DR
| Item | 1Password | Bitwarden |
|---|---|---|
| Price | Paid ($/mo) | Free + paid tiers |
| Security model | E2E + Secret Key (device-authenticated) | E2E + master password |
| CLI quality | ✅ Excellent (op CLI + biometric) | Good (bw CLI) |
| SSH integration | ✅ Native SSH agent | Manual |
| Git signing | ✅ commit signing via ssh key | Manual |
| Mobile / family share | ✅ | ✅ |
| Self-hosting | ❌ | ✅ (Vaultwarden) |
Recommendation: 1Password (better developer workflow integration). Bitwarden if cost-sensitive or self-hosting needed.
1. 1Password Setup
1.1 Install (Mac)
brew install --cask 1password 1password-cli1.2 Install (Windows)
winget install --id AgileBits.1Password -e
winget install --id AgileBits.1Password.CLI -e1.3 First Sign-In
Desktop app → sign in (Email + Secret Key + Master Password). The Secret Key came from your signup PDF or another device.
1.4 CLI ↔ Desktop Integration
Desktop → Settings → Developer → "Integrate with 1Password CLI" ✅. This is the key step — op commands authenticate via GUI biometric (Touch ID / Windows Hello).
Confirm:
op vault list
# Unlocks via Touch ID/Windows Hello, no password prompt2. SSH Key Integration (1Password)
Traditionally SSH keys are plaintext files at ~/.ssh/id_ed25519. 1Password ships a built-in SSH agent — keys live in the vault and biometric authorizes per use.
2.1 Generate the Key
1Password desktop → "+" → SSH Key:
- Name:
personal-ed25519 - Algorithm: Ed25519
- Key pair auto-generated
2.2 Enable the SSH Agent
Desktop → Settings → Developer → "Use the SSH agent" ✅
- macOS: auto-adds to
~/.ssh/config - Windows: auto-sets the env var
2.3 Register the Public Key with GitHub
1Password vault → that key item → "Public key" copy → GitHub → Settings → SSH and GPG keys → New SSH key.
2.4 Test
ssh -T git@github.com
# Hi yourname! You've successfully authenticated...
# (one Touch ID / Windows Hello tap)No plaintext key files in
~/.ssh/anymore. New machines just sign into 1Password and SSH works.
3. Git Commit Signing (with SSH Key)
Simpler than GPG, reuses the same key:
git config --global gpg.format ssh
git config --global user.signingkey "ssh-ed25519 AAAA... your-comment"
# Copy the public key from the 1Password item
git config --global commit.gpgsign trueNow git commit → 1Password biometric → auto-signed. Register the same public key on GitHub Settings → SSH and GPG keys → "Add new signing key".
4. .env / API Key Integration
Instead of plaintext .env, fetch from 1Password:
4.1 Add the Secret
1Password → "+" → API Credential:
- Title:
Anthropic API Key - Credential:
sk-ant-... - Tags:
dev,api
4.2 CLI Fetch
op item get "Anthropic API Key" --fields credential
# sk-ant-...4.3 op run — Auto-injection
.env.tmpl with placeholders only:
ANTHROPIC_API_KEY=op://Private/Anthropic API Key/credential
GITHUB_TOKEN=op://Private/GitHub/token
Run:
op run --env-file=.env.tmpl -- npm run dev
# The command runs with the real values injected as env vars.env.tmpl is safe to commit (references only). Actual secrets stay in the vault.
4.4 chezmoi Integration
From mac/dotfiles, a chezmoi template:
# dot_env.tmpl
export ANTHROPIC_API_KEY={{ onepasswordRead "op://Private/Anthropic/credential" }}
chezmoi apply auto-injects → produces a plaintext .env on the new machine.
5. Bitwarden — The Free Alternative
5.1 Install
# Mac
brew install --cask bitwarden bitwarden-cli
# Windows
winget install Bitwarden.Bitwarden
winget install Bitwarden.CLI5.2 Sign-in + Session
bw login email@example.com
# Master password → returns an API Key
# Export the session
export BW_SESSION="$(bw unlock --raw)"
# Or define a function in .zshrc:
function bwl { export BW_SESSION="$(bw unlock --raw)"; }5.3 Read Secrets
bw get item "Anthropic API"
bw get password "Anthropic API"
bw get notes "Some Long Note"JSON output, pairs well with jq:
bw get item "GitHub" | jq -r '.login.password'5.4 Weaknesses
- No SSH agent integration (you can store keys manually but they aren't auto-used)
- No automated Git commit signing
- Biometric integration depends on OS/app (less smooth than 1Password)
5.5 Self-Hosting (Vaultwarden)
# Mac/Linux docker
docker run -d \
--name vaultwarden \
-v ./vw-data:/data \
-p 8000:80 \
vaultwarden/server:latestRun on a home server and switch with bw config server http://your-server:8000. Bitwarden clients work as-is.
6. Two-Machine Workflow
Secrets added on Mac are immediately usable on Windows (vault sync is automatic):
# Add a new key on Mac
op item create --category="API Credential" \
--title="New Service" \
--vault="Private" \
credential="sk-..."
# Use it immediately in Windows pwsh
op item get "New Service" --fields credentialShare .env.tmpl itself across both machines via Git/Syncthing (values live only in vault — templates are safe).
Verification
op vault listorbw list folders— auth worksssh -T git@github.com— 1Password SSH agent authenticates with one Touch ID tapgit commit -S -m "test"→git log --show-signature→ "Good signature"op run --env-file=.env.tmpl -- env | grep MY_KEY→ real value injected- Sign into 1Password CLI on Windows → same vault accessible
Troubleshooting
op CLI Doesn't Pair with the GUI
- Desktop → Settings → Developer → "Integrate with 1Password CLI" missed
- Desktop must be running (signed in)
- macOS: System Settings → Security → grant biometric
Bitwarden Session Expires
Default 30 min idle lock. Run bw unlock --raw again. Don't put auto-unlock in .zshrc — the master password ends up in the environment.
Two SSH Agents (1Password vs ssh-agent)
Pin in ~/.ssh/config:
Host github.com
IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
On Windows, set SSH_AUTH_SOCK.
op run Mangles Quoting
Prefer op inject (clearer): op inject -i .env.tmpl -o .env.runtime && source .env.runtime. A plaintext file is created temporarily — delete after.
Family / Team Vault Permission Issues
1Password Business → per-vault permissions. The CLI's reachable vaults: op vault list. Commands fail without permission.
References
- mac/dotfiles — chezmoi + 1Password integration
- multi-os/file-sync — sync non-secret files like
.env.tmplvia Syncthing - 1Password CLI (official)
- Bitwarden CLI
- Vaultwarden (self-host)
Changelog
- 2026-05-12: First draft. 1Password vs Bitwarden comparison + SSH integration · Git signing · env auto-injection · two-machine workflow + five troubleshooting cases.