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.

When an application needs a secret, it doesn’t talk to the OS keychain directly. Instead, it connects to the keychain-auth daemon over a local socket. The daemon verifies exactly who is calling — at the kernel level — before it touches any stored credential.

Architecture overview

keychain-auth sits between your application and the native OS keychain. No client application ever queries the keychain directly.
┌──────────────────┐      Local Socket      ┌──────────────────┐     Native API     ┌──────────────┐
│  Client Application │ ◄──────────────────► │  keychain-auth   │ ◄────────────────►│  OS Keychain │
│  (e.g., CLI, app)   │   JSON-over-socket   │  (Security Daemon)│    (Read/Write)   │  (Storage)   │
└──────────────────┘                        └──────────────────┘                   └──────────────┘
The daemon runs as a background process. All keychain items are stored under service namespaces managed exclusively by keychain-auth, so no other process can access them by going around the daemon.

Connection-bound authentication

keychain-auth uses no session tokens, cookies, or API keys. The connection itself is the authenticated session. When you connect, the daemon immediately retrieves your process’s identity directly from the kernel — before you can send a single request. There is nothing to steal or replay, because there is nothing transmitted to prove identity.
The official client SDK opens the socket with O_CLOEXEC automatically. If you are building a custom client, you must set this flag yourself to prevent child processes from inheriting the authenticated connection.

Kernel PID verification

To prevent spoofing, the daemon ignores any process ID your application reports. It retrieves the real PID from the kernel transport layer using platform-specific mechanisms:
The daemon calls SO_PEERCRED on the Unix domain socket. The kernel returns a ucred structure containing the verified PID, UID, and GID of the connecting process. A process cannot forge these values.
macOS does not support SO_PEERCRED. The daemon queries the socket with the LOCAL_PEERPID option, which the kernel populates with the caller’s verified PID.
On Windows, the daemon calls GetNamedPipeClientProcessId on the active named pipe handle. The kernel enforces this value; it cannot be spoofed by the client.

SHA-256 binary hash check

Once the daemon has the verified PID, it resolves the path of the running executable on disk:
  • Linux: reads the symlink at /proc/[PID]/exe
  • macOS: calls proc_pidpath
  • Windows: calls QueryFullProcessImageName
It then reads the binary file and computes a SHA-256 hash. This hash is checked against your registered entries in the config.json file for your platform (on macOS: ~/Library/Application Support/keychain-auth/config.json; on Linux: ~/.config/keychain-auth/config.json).
Modern operating systems prevent running executables from being modified in place (ETXTBSY on Linux). This means the hash check happens against a file that cannot be swapped out mid-run, making the validation highly reliable.

Policy binding

After the identity check passes, the daemon re-reads config.json and binds the matching policy to your connection for its entire lifetime. That policy controls exactly which service namespaces you can read from, write to, and search — scoped to this connection only. If the hash does not match any registered entry, your connection is rejected and queued in the pending approval workflow. See Zero-trust access control policies for how policies are configured.

Connection lifecycle

Every interaction with keychain-auth follows this sequence:
  1. Connect — your application opens a socket connection to the daemon
  2. Verify — the daemon retrieves your PID from the kernel, resolves your binary path, and checks your SHA-256 hash
  3. Bind policy — the daemon attaches your registered access policy to the connection
  4. Handle requests — you send REQUEST payloads; the daemon enforces your policy on every operation
The connection closes when your application disconnects. There is no session expiry, no token rotation, and no state to manage between connections.