devAlice
← Multi-OS

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

Item1PasswordBitwarden
PricePaid ($/mo)Free + paid tiers
Security modelE2E + Secret Key (device-authenticated)E2E + master password
CLI quality✅ Excellent (op CLI + biometric)Good (bw CLI)
SSH integration✅ Native SSH agentManual
Git signing✅ commit signing via ssh keyManual
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-cli

1.2 Install (Windows)

winget install --id AgileBits.1Password -e
winget install --id AgileBits.1Password.CLI -e

1.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 prompt

2. 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 true

Now 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.CLI

5.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:latest

Run 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 credential

Share .env.tmpl itself across both machines via Git/Syncthing (values live only in vault — templates are safe).

Verification

  1. op vault list or bw list folders — auth works
  2. ssh -T git@github.com — 1Password SSH agent authenticates with one Touch ID tap
  3. git commit -S -m "test"git log --show-signature → "Good signature"
  4. op run --env-file=.env.tmpl -- env | grep MY_KEY → real value injected
  5. 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

Changelog

  • 2026-05-12: First draft. 1Password vs Bitwarden comparison + SSH integration · Git signing · env auto-injection · two-machine workflow + five troubleshooting cases.

Comments