--- title: BC-AuthPromp - Concept & Spec v0.1.00 robots: noindex, nofollow --- # BC-AuthPrompt: Draft Concept & v0.1.00 Specification * Version: **0.1.00 (draft)** * Status: **Prototype / exploratory** * Target environment: **CLI applications**, with particular focus on **Rust applications on macOS**, plus a **portable TTY fallback** with no persistent storage. --- ## 1. Overview AuthPrompt is a small, external helper invoked by command-line applications to obtain authentication secrets (passwords, passphrases, tokens) via a secure user experience. Core ideas: * The CLI application does **not** implement password UI or OS secret storage directly. * Instead, it spawns an **AuthPrompt helper** as a child process and communicates over a simple text protocol on stdin/stdout. * On **macOS**, the helper may: * Look up or store secrets in **Keychain**; and/or * Prompt the user via a native GUI, optionally using biometrics (Touch ID / Apple Watch) to unlock. * A **platform-agnostic TTY backend** provides a best-effort secure prompt with **no key storage**, suitable for all platforms. Each CLI can choose its own security requirements, including whether Keychain (or other storage) is allowed, required, or forbidden. --- ## 2. Goals 1. Provide a **consistent, process-external** mechanism for obtaining secrets for CLI tools. 2. Allow applications to **declare security policy**, including: * Whether secrets may be stored in an OS secret store. * Whether stored secrets may be used without re-prompting. 3. On macOS, **integrate with Keychain**, including optional biometric unlock when a secret is already stored. 4. Provide a **portable TTY fallback** with: * No persistent secret storage. * Best-practices for secure input (no echo, minimal exposure). 5. Keep the **protocol minimal and text-based**, suitable for easy implementation in multiple languages. 6. Avoid coupling to any particular application or ecosystem. --- ## 3. Non-goals * Not a full identity framework or SSO system. * Not a password manager UI. * Not a general IPC framework between arbitrary processes. * Not a key derivation or cryptographic library; it only surfaces secrets, it does not define how they are generated or used. --- ## 4. Terminology * **Client**: The CLI application that needs a secret (e.g., a Rust binary). * **Helper**: The `authprompt-*` program invoked by the client. * **OS Secret Store**: Platform-native storage (e.g., Keychain on macOS; other stores may be added on other platforms later). * **Secret**: Any sensitive value used for authentication (password, passphrase, token, etc.). --- ## 5. High-Level Architecture ### 5.1 Components * **Client application** (e.g., Rust CLI): * Spawns the helper process. * Sends a request describing: * What secret it needs (logical id). * The desired user-facing prompt text. * The policy for storage usage. * Receives either a secret, a cancellation, or an error. * **AuthPrompt helper** (`authprompt-mac`, `authprompt-tty`, etc.): * Reads request from stdin (line-based protocol). * Validates and interprets fields. * Decides which backend to use: * macOS Keychain + GUI. * TTY prompt with no storage. * Returns a response to stdout. * **Backends**: * **macOS GUI + Keychain backend**: * Optionally reads/writes secrets from/to Keychain depending on client policy. * Uses secure UI elements with no echo and respects platform best practices. * **TTY backend**: * Uses best-practice raw mode / no-echo input. * Does not perform any persistent secret storage. ### 5.2 Process Model * The client invokes the helper as a **short-lived child process** for each prompt: * No long-lived daemon is required in v0.1.0. * Caching, if any, is left to future versions or separate components. --- ## 6. Functional Requirements ### 6.1 Basic Prompting The helper must: * Display a prompt to the user based on client-provided text fields. * Read a secret from user input without echoing it. * Allow the user to **confirm** or **cancel**. * Return: * `OK` + secret (on success), * `CANCEL` (on user cancellation), * or `ERR` (on errors). ### 6.2 OS Secret Store Integration (macOS Keychain) On macOS, the helper may: * Look up existing secrets in Keychain using a logical identifier provided by the client. * If configured and allowed, store new secrets in Keychain. * Offer an optional UX choice like “Save in Keychain” when permitted. * Use platform facilities to unlock the secret (including biometrics) if configured and supported. The client decides: * Whether storage is allowed, forbidden, or required. * Whether retrieval from storage must be silent or may show a confirmation UI. * Whether the helper may prompt the user at all, or only perform storage operations (e.g., delete). ### 6.3 TTY Fallback The TTY backend must: * Operate without any dependency on platform GUI libraries. * Disable echo during password entry. * Avoid writing the secret to logs or screen. * Never perform persistent secret storage. * Be usable on: * Unix-like platforms (POSIX TTY). * Windows console (in future implementations). ### 6.4 Client-Defined Policy The client must be able to specify at minimum: * **Storage policy**: * No use of OS secret store. * Prefer stored secret, if present; otherwise prompt and store. * Prefer stored secret; if absent, prompt but **do not** store. * Retrieve only; do not prompt (get-only mode). * Delete stored secret; do not prompt. * **Interaction policy**: * Prompt allowed. * Prompt forbidden (retrieve-only or delete-only). --- ## 7. Security Requirements ### 7.1 Input Handling * The helper must ensure that secrets are never: * Echoed back to the terminal or GUI logs. * Stored in environment variables. * Written to disk, including temporary files. * The helper must clear sensitive data from memory buffers as early as reasonably possible. ### 7.2 Transport * The primary transport between client and helper is: * stdin/stdout pipes for the child process. * These are private to the process relationship between client and helper. * The protocol must not be multiplexed across multiple untrusted clients in this version. * The helper must not start any listening network sockets in v0.1.0. ### 7.3 OS Secret Store Usage (macOS Keychain) On macOS: * Secrets stored in Keychain must be tagged with: * A **service** name derived from a client-provided identifier. * Optional metadata fields for display (e.g., human-readable name). * The helper must: * Respect the client’s declared storage policy. * Not silently store secrets if the client has forbidden storage. * Not retrieve secrets from Keychain when the client has forbidden storage. * If biometrics are used: * Access control lists (ACLs) and Keychain attributes should be configured so that: * Only the current user can unlock the item. * Authentication UI is provided by the OS, not by the helper. ### 7.4 Logging * The helper must not log: * Secret contents. * Unredacted protocol lines that might contain secrets. * Non-secret information (e.g., error details, key identifiers) may be logged sparingly for debugging, but v0.1.0 assumes debug logs are disabled by default for production use. ### 7.5 TTY Secure Input * The TTY backend must set the terminal to: * No-echo mode. * Restore the original terminal settings even in the face of errors where possible. * It must handle interruptions (e.g., signals) gracefully and restore TTY state. --- ## 8. Protocol Specification (AuthPrompt v0.1.0) ### 8.1 Transport and Encoding * The client writes a **request** to the helper’s stdin. * The helper writes a **response** to stdout. * All data is **UTF-8** encoded. * Line endings are `\n`. * The protocol is text-based and line-oriented. ### 8.2 Message Structure #### 8.2.1 Request A request consists of: 1. A required `VERSION` line. 2. Zero or more `FIELD` lines. 3. A terminating `END` line. Example: ```text VERSION 1 FIELD id=com.example.myapp:signing-key:foo@example.com FIELD prompt=Enter password to unlock signing key FIELD description=This password protects your local signing key. FIELD secret_type=password FIELD store_policy=prefer_store_if_missing FIELD interaction_mode=get_or_prompt END ``` #### 8.2.2 Fields (v0.1.0) All `FIELD` lines have the form: ```text FIELD <name>=<value> ``` Names are case-sensitive; values may contain any UTF-8 characters except newline. Implementations should treat unknown fields as hints and ignore them unless otherwise specified. **Required fields:** * `id` * Logical identifier for the secret. * Used as the key for any OS secret store integration. * Example: `com.example.myapp:account:foo@example.com`. * `prompt` * Short, user-facing prompt string. * Example: `Enter password`. **Optional fields:** * `description` * Longer user-facing explanatory text. * `label` * Human-readable label for display in OS UI when using a secret store. * May be used as Keychain item name or equivalent. * `secret_type` * One of: * `password` * `passphrase` * `token` * `otp` * This is advisory; v0.1.0 treats all as opaque secrets for storage and UI purposes. * `store_policy` * Controls how OS secret storage may be used. Values: * `forbid` * Do not read from or write to any OS secret store. * `allow_store_if_missing` * Prefer an existing stored secret; if missing, prompt, then **optionally** store based on UX (e.g., “Save in Keychain?”). * `prefer_store_if_missing` * Same as `allow_store_if_missing`, but UX should default to storing (subject to OS conventions). * `no_store` * Allow reading from store (if present), but do not write new values. * `get_only` * Only attempt to read from store; do not prompt. If not present, fail. * `interaction_mode` * Controls user interaction. Values: * `get_or_prompt` * Default. Try store (if allowed); otherwise prompt. * `prompt_only` * Always prompt; do not attempt to read from store, but may write based on `store_policy`. * `get_only` * Do not prompt. Only read from storage if allowed. * `delete_only` * Delete any stored secret associated with `id`. Do not prompt or return a secret. * `min_length` * Integer string. Advisory minimum length for secrets in UI; the helper may warn or prevent submission if shorter. * `max_length` * Integer string. Advisory maximum length; the helper may truncate or disallow longer input, but v0.1.0 does not require enforcement. The helper should treat unrecognized field names as non-fatal hints. ### 8.3 Responses Responses are one of three forms: #### 8.3.1 Success ```text OK <secret-bytes> ``` * `<secret-bytes>` is the secret as a single line of UTF-8 text. * The application must treat the entire substring after the space as the secret until end-of-line. * v0.1.0 does **not** define escaping or binary encoding; if binary data is needed, clients may base64-encode application-side. #### 8.3.2 Cancellation ```text CANCEL ``` * Indicates that the user or helper chose to cancel the request (e.g., the user closed the dialog). #### 8.3.3 Error ```text ERR <error-code> <message> ``` * `<error-code>` is a machine-readable identifier (e.g., `no_store_backend`, `invalid_request`, `backend_error`). * `<message>` is a human-readable description. ### 8.4 Exit Codes The helper should also set its process exit code: * `0` — Success (`OK`). * `1` — User cancellation (`CANCEL`). * `>= 10` — Internal or backend error (`ERR ...`). The client should primarily rely on the textual response; exit codes are a secondary signal. --- ## 9. macOS Backend Behavior (v0.1.0) ### 9.1 Keychain Item Model For `secret_type=password` and related types: * Store as a **generic password** item. * Suggested mapping: * `kSecAttrService` = `id` field. * `kSecAttrAccount` = optional logical account component (if encoded in `id`, this may be extracted by convention). * `kSecAttrLabel` = `label` field, or a derived human-readable name. Access control: * The item should be accessible only to the current user. * If biometrics are used, configure access control to allow biometric-based unlock based on user settings and OS constraints. ### 9.2 Lookup Behavior When storage is allowed (per `store_policy` and `interaction_mode`): 1. Look up the Keychain item using `id` and associated attributes. 2. If present: * Use the OS-provided UI to unlock as needed. * If unlock succeeds, return `OK <secret>` without additional prompting. ### 9.3 Store Behavior When storing is allowed by policy: 1. After a successful prompt (GUI or TTY), the helper may: * Offer a “Save in Keychain” checkbox (if appropriate). * If the user consents, write the secret to Keychain using the mapping above. 2. If the client specified `store_policy=prefer_store_if_missing`, the helper should default to storing when possible, but must respect user refusal if the OS UI allows that. ### 9.4 Delete Behavior For `interaction_mode=delete_only`: * The helper deletes any Keychain item matching the `id` and permitted attributes. * No GUI prompt for a secret is displayed. * A successful delete returns `OK` with an empty secret (or a short diagnostic string); v0.1.0 leaves the exact payload for delete success to implementation, but recommends: ```text OK ``` to avoid confusion with real secrets. --- ## 10. TTY Backend Behavior (v0.1.0) ### 10.1 Input Handling * On POSIX systems: * Use termios or equivalent to disable echo. * Read input until newline. * Restore terminal settings. * On non-POSIX systems: * Use equivalent console APIs to disable echo and read a line. ### 10.2 Output * Show the `prompt` field followed by `: ` or similar. * If `description` is provided, print it above or below the prompt. * Never echo the entered secret. ### 10.3 Storage * The TTY backend must ignore any `store_policy` values that imply persistent storage. * Its behavior with respect to storage: * `forbid`, `no_store`, `get_or_prompt`, `prompt_only`: treat as “prompt only, no store.” * `allow_store_if_missing`, `prefer_store_if_missing`, `get_only`, `delete_only`: * Act as if storage is not available: * For `get_only` or `delete_only`, return an error (`ERR no_store_backend`). * For others, proceed with prompt-only behavior. ### 10.4 Error Handling * On errors (e.g., failure to set TTY modes), the helper should: * Restore any modified TTY state. * Return an `ERR` response with an appropriate error code. --- ## 11. Rust Client Sketch (Non-normative) The following describes an expected usage pattern for a Rust client. This is explanatory and not part of the normative spec. 1. Construct a request: * Build a sequence of lines: * `VERSION 1` * `FIELD ...` * `END` 2. Spawn the helper: * Use `std::process::Command` to start `authprompt-mac` or `authprompt-tty`. * Connect stdin/stdout. 3. Send the request and read a single-line response. 4. Interpret the response: * If it begins with `OK` and has a space, treat the rest as the secret. * If it is exactly `OK`, treat as success with an empty secret (e.g., delete operations). * If `CANCEL`, surface as user cancellation. * If `ERR`, parse `<error-code>` and `<message>` for diagnostics. 5. Clear the secret from intermediate buffers as soon as it is no longer needed. --- ## 12. Versioning and Extensibility * The protocol version is indicated by `VERSION <int>` at the start of the request. * v0.1.0 defines `VERSION 1`. * Helpers must: * Accept `VERSION 1`. * Reject unknown versions with `ERR unsupported_version`. * Future extensions may: * Add new field names. * Add new values to existing fields. * Add multi-line or structured responses, guarded by new version numbers. Implementations must ignore unknown `FIELD` names to permit forward compatibility. --- ## 13. Summary AuthPrompt defines: * A **stand-alone helper binary** that CLI applications can invoke to obtain secrets securely. * A **simple, line-based protocol** that allows clients to specify: * Prompt text. * Logical identifiers. * Storage and interaction policies. * A **macOS path** that can leverage Keychain and native UX, including biometrics when appropriate. * A **portable TTY fallback** that offers secure input with no persistent storage. This v0.1.0 draft is intended as a foundation for experimentation and early implementations, particularly for Rust-based CLI applications on macOS, while remaining extensible to other platforms and backends in future revisions. Below is a **stand-alone Appendix** intended to accompany the AuthPrompt draft specification. It introduces the research background, explains the absence of an existing solution that matches AuthPrompt’s goals, and surveys prior art and best practices with links to relevant documentation. --- # Appendix A — Prior Art, Background Research, and Best Practices ## A.1. Overview AuthPrompt aims to provide a **generic, cross-tool, text-protocol-driven helper** that can: * Act as a secure, out-of-process prompt for secrets, * Communicate via a **stdin/stdout protocol**, * Optionally integrate with **OS-level secret stores** (such as macOS Keychain), * Provide both a **GUI UX layer** and a **portable TTY fallback**, and * Allow each calling CLI application to **declare its own security policy**. During research for this specification, no existing tool or library was found that fully meets this combination of goals. Several existing systems implement *parts* of this design—sometimes extremely well—but none combine these capabilities into a neutral, reusable, cross-platform component suitable for arbitrary CLI applications. The following sections survey the closest related systems and outline best practices inferred from them. --- ## A.2. Git Credential Helpers Git includes a well-designed helper mechanism that is conceptually the closest precedent for AuthPrompt. It consists of: * A **stdin/stdout protocol** for exchanging credential requests/responses, * A set of **pluggable helpers** that can retrieve or store credentials using OS-level secret stores, and * A clear separation between: * Git (the client) * The helper (an external process) * The OS secret store (Keychain, Secret Service, etc.) ### Relevance to AuthPrompt Git’s helpers demonstrate that: * A small, line-oriented protocol is sufficient for secure CLI–helper communication. * External helper processes are a clean architectural pattern. * OS secret store integrations can be layered onto this model. ### Useful links * Git Credential System [https://git-scm.com/docs/gitcredentials](https://git-scm.com/docs/gitcredentials) * Git Credential Helper Protocol [https://git-scm.com/docs/git-credential](https://git-scm.com/docs/git-credential) * macOS Keychain helper (`git-credential-osxkeychain`) [https://github.com/git/git/blob/master/contrib/credential/osxkeychain/git-credential-osxkeychain.c](https://github.com/git/git/blob/master/contrib/credential/osxkeychain/git-credential-osxkeychain.c) * Linux Secret Service helper (`git-credential-libsecret`) [https://github.com/git/git/blob/master/contrib/credential/libsecret/git-credential-libsecret.c](https://github.com/git/git/blob/master/contrib/credential/libsecret/git-credential-libsecret.c) * Windows Credential Manager helper (`git-credential-wincred`) [https://github.com/git/git/blob/master/contrib/credential/wincred/git-credential-wincred.c](https://github.com/git/git/blob/master/contrib/credential/wincred/git-credential-wincred.c) --- ## A.3. GnuPG Pinentry System The GnuPG project provides **pinentry** programs—small external helpers that display GUI or TTY dialogs to collect passphrases. Pinentry variants exist for curses, Qt, GTK, macOS, and others. ### Relevance to AuthPrompt Pinentry demonstrates: * A **minimal helper program** can provide secure input without exposing secrets to the calling application’s environment. * A clearly defined **protocol over stdin/stdout** (Assuan) works well for CLI/GUI separation. * Platform-appropriate UX can be handled outside the main application. ### Limitations relative to AuthPrompt goals * Pinentry does **not** integrate directly with OS-secret stores. * The protocol is tightly bound to the GnuPG agent model. * The system is not meant to be a generic prompting mechanism for arbitrary tools. ### Useful links * Pinentry project [https://www.gnupg.org/software/pinentry/index.html](https://www.gnupg.org/software/pinentry/index.html) * Assuan protocol (GnuPG IPC) [https://www.gnupg.org/software/libassuan/](https://www.gnupg.org/software/libassuan/) --- ## A.4. macOS Keychain and the `security` CLI macOS provides a robust OS-level password store (Keychain) accessible via: * The **Keychain Services API**, and * The **`security` command-line tool**, which supports password queries, addition, deletion, and controlled user interaction. The Keychain can enforce authentication policies such as: * User approval dialogs, * Touch ID / Apple Watch / passcode authentication, * Application-level ACLs. ### Relevance to AuthPrompt Keychain represents the strongest model of a **secure OS-managed credential store** available to CLI tools without requiring additional daemons. Its built-in UX and authentication prompts demonstrate best practices for secret access. ### Useful links * Keychain Services Programming Guide [https://developer.apple.com/documentation/security/keychain_services](https://developer.apple.com/documentation/security/keychain_services) * `security` CLI tool [https://ss64.com/osx/security.html](https://ss64.com/osx/security.html) (Alternative reference: `man security` on macOS) --- ## A.5. Linux Secret Service API Many Linux desktop environments implement the **Secret Service** API, a DBus-based system for storing and retrieving secrets. Implementations include: * GNOME Keyring [https://wiki.gnome.org/Projects/GnomeKeyring](https://wiki.gnome.org/Projects/GnomeKeyring) * KWallet (via compatibility layers) [https://develop.kde.org/docs/kwallet/overview/](https://develop.kde.org/docs/kwallet/overview/) * KeePassXC (optional Secret Service mode) [https://github.com/keepassxreboot/keepassxc/blob/develop/docs/SECRET_SERVICE.md](https://github.com/keepassxreboot/keepassxc/blob/develop/docs/SECRET_SERVICE.md) Bindings: * `libsecret` [https://developer.gnome.org/libsecret/](https://developer.gnome.org/libsecret/) * Python `secretstorage` [https://pypi.org/project/secretstorage/](https://pypi.org/project/secretstorage/) ### Relevance to AuthPrompt Secret Service shows how a **desktop OS** can provide: * A unified password store, * With unlock prompts, * Exposed via a standardized **IPC protocol**. While the protocol is DBus-based (not stdin/stdout), it informs AuthPrompt’s approach to secure storage and UX. --- ## A.6. Windows Credential Manager Windows includes the **Credential Manager**, which stores credentials securely and exposes APIs for retrieving them with user approval. ### Relevance to AuthPrompt It serves as the primary OS secret storage backend for tools that need persistent secrets, and is used by several Git credential helpers. ### Useful links * Credential Manager Overview [https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-manager](https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-manager) * Win32 Credential Management API [https://learn.microsoft.com/en-us/windows/win32/api/wincred/](https://learn.microsoft.com/en-us/windows/win32/api/wincred/) --- ## A.7. Askpass Frameworks (Unix/macOS) A variety of tools use an `askpass` mechanism where an external helper binary performs secure prompting. Examples include: * `SUDO_ASKPASS` for sudo [https://www.sudo.ws/man/1.8.27/sudo.man.html#ASKPASS](https://www.sudo.ws/man/1.8.27/sudo.man.html#ASKPASS) * Git’s `GIT_ASKPASS` and SSH’s `SSH_ASKPASS` mechanisms [https://git-scm.com/docs/git-gui#_using_askpass](https://git-scm.com/docs/git-gui#_using_askpass) [https://man.openbsd.org/ssh#SSH_ASKPASS](https://man.openbsd.org/ssh#SSH_ASKPASS) ### Relevance to AuthPrompt These mechanisms demonstrate the long-standing Unix practice of: * Delegating secure UI prompting to an **external helper**, and * Using simple stdout-returned secrets. However: * There is no OS-secret-store integration, * No cross-tool standardization, * No unified schema beyond returning a single secret. --- ## A.8. Cross-Project Observations and Best Practices The following best practices emerge from surveying existing systems: ### A.8.1. Use an external process for secret entry * Avoid prompting within the main process to reduce exposure. * External helpers keep the secret out of environment variables, arguments, and history. ### A.8.2. Prefer line-oriented stdin/stdout protocols * Human-readable and debuggable. * Easy to implement in any language. * Proven successful in Git and GnuPG ecosystems. ### A.8.3. Integrate with OS secret stores when allowed * OS secret stores provide: * Better UX (biometrics / system dialogs), * Hardware-backed protection, * Stronger security boundaries. ### A.8.4. Give the *client* control over policy Different applications have different trust models. The helper should not assume: * Whether storage is acceptable, * Whether prompting is allowed, * Whether biometrics are permitted, * Whether secrets should be returned in plain text or not cached. The protocol must allow the client to declare these preferences. ### A.8.5. Provide a TTY fallback with zero storage When graphical environments or OS stores are unavailable, CLI tools still need: * A secure, no-echo password prompt, * With deterministic behavior, * And no persistent storage. ### A.8.6. Avoid adopting heavyweight protocols unnecessarily While DBus and Assuan are powerful, a lighter protocol is appropriate for simple CLI workflows where: * A short-lived process is spawned, * Only one request/response occurs per invocation, * Portability across OSes and runtimes matters. --- ## A.9. Summary Although many existing tools provide elements of secure prompting, secret storage, or helper-based architectures, none combine: * A **generic**, * **Cross-tool**, * **Cross-platform**, * **Stdin/stdout text protocol**, * With **optional OS secret store integration**, * Plus **configurable security policy** and **portable TTY fallback**. AuthPrompt’s design draws on well-established patterns from Git, GnuPG, macOS Keychain, Linux Secret Service, and askpass frameworks, assembling them into a unified and reusable specification intended for general CLI applications.