Skip to main content

KeePassXC SSH Agent

keepassxc-ssh-agent is a cross-platform (macOS and Linux) SSH IdentityAgent proxy that automatically triggers KeePassXC database unlock (via TouchID / Quick Unlock on macOS, biometric / password unlock on Linux) when an SSH key is needed.

Similar to how Strongbox handles SSH keys, this tool sits between your SSH client and the system ssh-agent. When SSH requests a key that isn't loaded (because the KeePassXC database is locked), the proxy triggers KeePassXC's unlock dialog. After you authenticate with TouchID, KeePassXC pushes the keys to ssh-agent, and the SSH operation continues seamlessly.

Functionality demonstration

KeePassXC SSH Agent based on KeePassXC Browser API.

Prerequisites

  • macOS or Linux (uses Unix sockets and KeePassXC's browser extension socket; on Linux the socket path is resolved from XDG_RUNTIME_DIR, supporting native and Flatpak installs)
  • Python >= 3.10
  • KeePassXC with:
    • Browser Integration enabled (Settings > Browser Integration > Enable browser integration) KeePassXC Browser Integration Settings screenshot
    • SSH Agent Integration enabled (Settings > SSH Agent > Enable SSH Agent integration) SSH-Agent settings screenshot
    • SSH keys configured with "Add key to agent when database is opened/unlocked" SSH-Key entry settings screenshot

Usage

usage: keepassxc-ssh-agent [-h] [--socket SOCKET] [--config CONFIG]
                           [--timeout TIMEOUT] [-v]
                           {install,run,status,uninstall} ...

SSH IdentityAgent proxy that triggers KeePassXC database unlock via TouchID

positional arguments:
  {install,run,status,uninstall}
    install             Associate with KeePassXC and set up the auto-start service
    run                 Start the SSH agent proxy (default command)
    status              Check connection status with KeePassXC
    uninstall           Remove the auto-start service and restore SSH_AUTH_SOCK

options:
  -h, --help          show this help message and exit
  --socket SOCKET     Path for the agent Unix socket
                      (default: ~/.keepassxc/agent.sock)
  --config CONFIG     Path to config file
                      (default: ~/.keepassxc/ssh-agent.json)
  --timeout TIMEOUT   Timeout in seconds for unlock prompt (default: 30)
  -v, --verbose       Enable verbose logging

How It Works

SSH Client ──► SSH agent protocol ──► keepassxc-ssh-agent (proxy)
                                             │
                                             ├─► SSH agent protocol ──► System ssh-agent
                                             │   (forward requests / replay after unlock)
                                             │
                                             └─► Browser extension protocol ──► KeePassXC
                                                 (trigger unlock when keys missing)
  1. SSH client connects to the proxy socket and requests identities or a signature
  2. Proxy forwards the request to the system ssh-agent
  3. If ssh-agent returns keys/signature, proxy passes it through (no delay)
  4. If ssh-agent returns empty/failure (DB is locked, keys not loaded):
    • Proxy connects to KeePassXC via the browser extension protocol
    • Sends get-databasehash with triggerUnlock to show the unlock dialog
    • Polls until the database is unlocked or timeout expires
    • KeePassXC pushes SSH keys to ssh-agent on unlock (asynchronously)
    • Proxy then polls ssh-agent until the key appears (rather than retrying once), so the very first request succeeds, and returns the result

SSH_AUTH_SOCK Interception

The proxy automatically intercepts SSH_AUTH_SOCK on startup by renaming the system ssh-agent socket (e.g. /tmp/com.apple.launchd.XXX/Listeners on macOS, /run/user/UID/ssh-agent.socket on Linux) to a .system backup and placing a symlink from the original path to the proxy socket. All SSH clients then connect to the proxy transparently. The proxy forwards requests to the renamed .system socket.

On shutdown, the proxy restores the original socket. No separate service or SSH config is needed — the run command handles everything.

Note (Linux/systemd): a systemd --user service starts with a clean environment and does not inherit your shell's SSH_AUTH_SOCK. install therefore captures the current SSH_AUTH_SOCK and bakes it into the generated unit (Environment=SSH_AUTH_SOCK=...) so interception works without any shell-profile changes.

Install

Make sure KeePassXC is running and unlocked with browser integration enabled, then:

Homebrew (macOS, recommended)

See homebrew homepage on how to setup homebrew.

brew install mietzen/tap/keepassxc-ssh-agent
keepassxc-ssh-agent install --register-only
brew services start keepassxc-ssh-agent

This will:

  • Install keepassxc-ssh-agent and its dependencies
  • Register with KeePassXC (you'll need to approve the association in the unlocked KeePassXC window)
  • Start the background service via Homebrew (auto-starts on login)

pipx - Automatic Install (macOS and Linux)

See pipx installation guide on how to setup pipx.

pipx install keepassxc-ssh-agent
keepassxc-ssh-agent install -y

This will:

  • Generate encryption keys for the browser protocol
  • Request association with KeePassXC (you'll need to approve it in the KeePassXC window)
  • Save the agent configuration to ~/.keepassxc/ssh-agent.json
  • Save the browser API credentials to ~/.keepassxc/browser-api.json (shared with keepassxc-cli if installed)
  • Set up an auto-start service for login: a LaunchAgent on macOS, or a systemd user service (~/.config/systemd/user/keepassxc-ssh-agent.service) on Linux

The -y flag auto-accepts all prompts. Without it, you'll be asked interactively whether to set up the auto-start service.

On Linux, manage the service with systemctl --user:

systemctl --user status keepassxc-ssh-agent     # check status
systemctl --user restart keepassxc-ssh-agent    # restart
journalctl --user -u keepassxc-ssh-agent        # view logs

systemd --user services require an active user session. On headless machines (no graphical login), enable lingering so the service starts at boot: loginctl enable-linger $USER.

pipx - Manual Install

If you want more control over the installation, you can split it into steps:

1. Install the package

pipx install keepassxc-ssh-agent

2. Register with KeePassXC

Register with KeePassXC without setting up the auto-start service:

keepassxc-ssh-agent install --register-only

You'll need to approve the association in the KeePassXC window when prompted.

3. Set up auto-start (optional)

macOS — create a LaunchAgent plist:

cat << 'EOF' > ~/Library/LaunchAgents/org.keepassxc.ssh-agent.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>org.keepassxc.ssh-agent</string>
  <key>ProgramArguments</key>
  <array>
    <string>/path/to/keepassxc-ssh-agent</string>
    <string>run</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
  <key>StandardOutPath</key>
  <string>/tmp/keepassxc-ssh-agent.out.log</string>
  <key>StandardErrorPath</key>
  <string>/tmp/keepassxc-ssh-agent.err.log</string>
</dict>
</plist>
EOF
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/org.keepassxc.ssh-agent.plist

Replace /path/to/keepassxc-ssh-agent with the actual path (find it with which keepassxc-ssh-agent).

Linux — create a systemd user unit:

mkdir -p ~/.config/systemd/user
cat << EOF > ~/.config/systemd/user/keepassxc-ssh-agent.service
[Unit]
Description=KeePassXC SSH Agent proxy
After=ssh-agent.service

[Service]
Type=simple
ExecStart=$(which keepassxc-ssh-agent) run
Environment=SSH_AUTH_SOCK=${SSH_AUTH_SOCK}
Restart=on-failure

[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now keepassxc-ssh-agent.service

The Environment=SSH_AUTH_SOCK=... line captures your current agent socket so the proxy can intercept it (the service otherwise runs with a clean environment).

Or start manually without an auto-start service:

keepassxc-ssh-agent run

Uninstall

Homebrew (macOS)

brew services stop keepassxc-ssh-agent
brew uninstall keepassxc-ssh-agent
rm -rf ~/.keepassxc  # Remove config (optional)

pipx

keepassxc-ssh-agent uninstall -y
pipx uninstall keepassxc-ssh-agent

This stops and removes the auto-start service (LaunchAgent on macOS, systemd user service on Linux), restores the original SSH_AUTH_SOCK socket, and removes the config directory (~/.keepassxc/). Without -y, you'll be asked before deleting the config directory.

Manual Uninstall

1. Stop and remove the auto-start service

macOS:

launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/org.keepassxc.ssh-agent.plist 2>/dev/null
rm -f ~/Library/LaunchAgents/org.keepassxc.ssh-agent.plist

Linux:

systemctl --user disable --now keepassxc-ssh-agent.service 2>/dev/null
rm -f ~/.config/systemd/user/keepassxc-ssh-agent.service
systemctl --user daemon-reload

2. Restore SSH_AUTH_SOCK

If the agent was running, it restores the original socket on shutdown automatically. If the system socket is still symlinked (e.g. after a crash), reboot or restore manually:

# Find the original socket path
SYSTEM_AGENT=$(cat ~/.keepassxc/ssh-agent.json | python3 -c 'import json,sys; print(json.load(sys.stdin).get("system_agent_path",""))')
# Remove the symlink and restore the backup
rm -f "$SYSTEM_AGENT"
mv "${SYSTEM_AGENT}.system" "$SYSTEM_AGENT"

3. Remove config and socket

rm -rf ~/.keepassxc

4. Uninstall the package

pipx uninstall keepassxc-ssh-agent

Known Limitations

  • macOS and Linux only: Relies on KeePassXC's browser extension Unix socket, whose path is platform-specific ($TMPDIR/org.keepassxc.KeePassXC.BrowserServer on macOS, $XDG_RUNTIME_DIR/.../org.keepassxc.KeePassXC.BrowserServer on Linux)
  • Linux auto-start: Uses a systemd --user service, which requires an active user session (use loginctl enable-linger for headless setups)
  • DB unlocked but agent cleared: If the database is already unlocked but ssh-agent keys were manually removed (ssh-add -D), the proxy detects empty keys and triggers "unlock", but KeePassXC reports "already unlocked" without reloading keys. Workaround: lock and re-unlock the database in KeePassXC.
  • Multiple databases: triggerUnlock only works for the currently active database tab in KeePassXC.

Development

This package depends on keepassxc-browser-api, which handles the KeePassXC browser extension protocol. The browser API credentials are stored in ~/.keepassxc/browser-api.json and are shared with keepassxc-cli if installed.

git clone https://github.com/mietzen/keepassxc-ssh-agent
git clone https://github.com/mietzen/keepassxc-browser-api
cd keepassxc-ssh-agent

python3 -m venv .venv
source .venv/bin/activate

# Install local keepassxc-browser-api dependency first
pip install ../mietzen-keepassxc-browser-api/

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest --tb=short -q

# Run tests with coverage
pytest --cov=keepassxc_ssh_agent --cov-report=term-missing

# Lint
ruff check --ignore=E501 --exclude=__init__.py ./keepassxc_ssh_agent

Release files for keepassxc-ssh-agent 1.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for keepassxc-ssh-agent 1.6.0
File Size Uploaded
keepassxc_ssh_agent-1.6.0.tar.gz 4.5 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for keepassxc-ssh-agent 1.6.0
File Interpreter ABI Platform
keepassxc_ssh_agent-1.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 4.5 MB

Release files / keepassxc_ssh_agent-1.6.0.tar.gz

Download URL keepassxc_ssh_agent-1.6.0.tar.gz
Size 4.5 MB
Tags Source
SHA-256 checksum
How to use checksums
aa9f6bcbf9a863faf59e445fd213900933697c5a3eedffc98fc10faf092bb28a
BLAKE2b-256 checksum
How to use checksums
7de3ec5966a7165f619e063b37d26a8c55d4c0bf5a2632c081d16005b9c8c6c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.

Transparency log

Release files / keepassxc_ssh_agent-1.6.0-py3-none-any.whl

Download URL keepassxc_ssh_agent-1.6.0-py3-none-any.whl
Size 20.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
17b7ab7f50d7eb037f5fb4219408b1409bf3b0a07c9e4a70f734f2ed94d0bebe
BLAKE2b-256 checksum
How to use checksums
d56052ab45a0377090a93e0e31c26565ace2e5809195f29dd95439a5b64ccb61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.6.0 This release

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

1 release file

0.6.0

1 release file

0.5.0

1 release file

0.4.0

1 release file

0.3.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page