Skip to main content

Documentation Index

Fetch the complete documentation index at: https://theseventeen-2abbdf80.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

On macOS, keychain-auth listens on a Unix domain socket and uses the LOCAL_PEERPID kernel option to retrieve the true PID of every connecting process. It resolves that PID to an executable path using proc_pidpath, computes a SHA-256 hash of the binary, and checks it against your approved policy before touching Apple Keychain Services on your behalf.

The problem: macOS prompt fatigue

macOS SecurityAgent is designed for signed GUI application bundles. Command-line tools are often compiled locally, run inside virtual environments, or distributed unsigned, so macOS cannot uniquely identify them. The result is a constant stream of dialogs: “your-cli wants to use your keychain. Enter your password.” Over time, users click Always Allow out of frustration. Once clicked, macOS grants access to that keychain item to any command-line invocation — completely bypassing the boundary the dialog was meant to create. keychain-auth eliminates the prompt cycle. Your approved CLI tools connect to the daemon silently; the daemon handles the single, stable entry in Apple Keychain under its own service namespace, and SecurityAgent prompts you only once (if at all) to grant the daemon itself access.

Socket path

The daemon listens on a Unix domain socket in your macOS user Library:
~/Library/Application Support/keychain-auth/agent.sock
The socket is created with 0600 permissions so only your user account can connect to it.

Kernel-level process verification

When a client connects, the daemon calls GetsockoptInt with the LOCAL_PEERPID socket option on the SOL_LOCAL level. This retrieves the PID directly from the kernel — the connecting process has no way to forge it. With the verified PID in hand, the daemon calls proc_pidpath to resolve the absolute path of the running executable on disk. It then reads the binary file and computes a SHA-256 hash. Because macOS locks running executables from in-place modification (ETXTBSY), the hash of a running binary reflects exactly what you approved.

Code signature context

GUI applications on macOS carry code signatures that SecurityAgent uses to identify them. CLI tools typically do not. keychain-auth provides an equivalent guarantee for CLI tools through its hash-based approval model:
  • The first time an unregistered binary connects, the daemon rejects it gracefully and queues it in ~/Library/Application Support/keychain-auth/pending.json.
  • You inspect the queue with keychain-auth list-pending and approve the binary by hash with keychain-auth approve <hash>.
  • From that point forward, that exact binary — verified by its SHA-256 hash — is the only version that can access the secrets you have scoped to it.
When you update a CLI tool (e.g. upgrade via Homebrew), its binary changes and its hash no longer matches. Run keychain-auth upgrade $(which your-tool) after every update to refresh the approved hash without losing your access policy.

Apple Keychain Services backend

The daemon reads and writes secrets through Apple Keychain Services. Secrets are stored as generic password items, scoped to the service namespace you configure. The daemon manages all Keychain API calls on your behalf — you interact only through the keychain-auth socket protocol. The audit log at ~/Library/Logs/keychain-auth/audit.log records every approved and denied access attempt, including the binary path, hash, and targeted secret names. Plaintext values are never written to the log.

The O_CLOEXEC requirement

If your application forks a child process after connecting to the daemon, the child inherits all open file descriptors by default — including the live, already-authenticated socket. That child could then send requests to the daemon as if it were your trusted application. To prevent this, always open the socket with SOCK_CLOEXEC:
fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
This tells the kernel to close the file descriptor automatically on any exec() call, blocking the attack entirely. The official keychain-auth SDK handles this for you automatically.
If you write a custom client that does not set SOCK_CLOEXEC, any subprocess your application spawns could silently read or write keychain secrets using your authorized session. Always use the official SDK or set the flag explicitly.

Quick-start

# Start the daemon
keychain-auth start

# Register your CLI tool (run once during setup)
keychain-auth register $(which your-cli-tool)

# Check what the daemon has queued for approval
keychain-auth list-pending

# Approve a binary by its hash
keychain-auth approve sha256:<hash>
The configuration file lives at ~/Library/Application Support/keychain-auth/config.json. The audit log is written to ~/Library/Logs/keychain-auth/audit.log.