From 41786b863928c34403f27add86a1f57b539c1a49 Mon Sep 17 00:00:00 2001 From: Asim Awdah Date: Thu, 29 Oct 2026 22:05:54 +0300 Subject: [PATCH 1/3] docs: enhance README for clarity and structure; update installation and usage instructions --- README.md | 479 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 423 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index e45d7b0..36f0c33 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,44 @@ # OpenKey CLI -open-source developer command-line interface for the -[OpenKey](https://github.com/OpenSelfHosting/OpenKey) self-hosted, -end-to-end encrypted password manager. +OpenKey CLI is the command-line companion for the self-hosted, end-to-end encrypted [OpenKey](https://github.com/OpenSelfHosting/OpenKey) password manager. -Generate passwords offline, manage developer secrets through the unlocked **desktop or Android** app (native bridge), discover SSH / `.env` / API / AWS material into a device-grouped Secrets section, and optionally authenticate to a self-hosted sync server for ciphertext pull and a short-lived `OPENKEY_SESSION`. +It lets you: + +- generate secure passwords offline +- manage developer secrets from an unlocked OpenKey desktop or Android app +- discover SSH keys, `.env` files, API tokens, AWS credentials, and other sensitive material +- export selected values into your shell or child processes +- optionally sync encrypted data with a self-hosted OpenKey server Full documentation: [CLI guide](https://openkey.openselfhosting.com/guide/cli). ## Requirements -- Node.js **20+** -- For vault commands without a server: OpenKey **desktop** (or Android) app unlocked on this machine -- For server mode: a running [OpenKey_server](https://github.com/OpenSelfHosting/OpenKey_server) instance +- Node.js 20 or newer +- For local vault access without a server: an unlocked OpenKey desktop app or Android app on the same machine +- For server-backed usage: a running [OpenKey_server](https://github.com/OpenSelfHosting/OpenKey_server) instance ## Install -**From npm** (recommended): +### From npm (recommended) ```bash npm install -g openkey-cli openkey --version ``` -**From source** (development): +### From source ```bash cd openkey_cli npm install npm run build -npm link # optional: puts `openkey` on your PATH +npm link ``` -Without linking: +`npm link` is optional, but it makes the `openkey` binary available globally on your PATH. + +### Run without linking ```bash npx openkey-cli --help @@ -40,89 +46,458 @@ npx tsx src/cli.ts --help node dist/cli.js --help ``` -## Quick start (desktop bridge) +## Quick start + +These examples assume the OpenKey desktop app is already unlocked and running locally. ```bash -# Unlock the OpenKey desktop app first +# health check openkey status + +# generate a password without needing a vault openkey gen -l 24 --no-symbols + +# preview discovered secrets without saving anything openkey discover --dry-run + +# import discovered values into a device collection openkey discover -y + +# add a secret manually openkey secret add --name "GitHub PAT" --kind apiToken --secret ghp_... + +# add a secret from stdin printf '%s' 'ghp_...' | openkey secret add -n "GitHub PAT" --stdin + +# list secrets in the vault openkey secret list openkey secret list -d laptop -k apiToken -openkey secret update "GitHub PAT" --stdin < token.txt + +# export a device-specific .env file openkey secret export -d laptop -o .env.local -openkey secret devices + +# copy a secret to the clipboard and clear it after 45s openkey secret copy "GitHub" + +# show a TOTP code and copy it openkey totp "GitHub" -c + +# fetch a field from a matching item openkey get "GitHub" --field username + +# search by name or content openkey search api -eval $(openkey env DATABASE_URL GITHUB_TOKEN) + +# export env vars for the current shell +eval "$(openkey env DATABASE_URL GITHUB_TOKEN)" + +# run a command with secrets injected into its environment openkey run -e DATABASE_URL -e GH=GitHub -- npm start ``` -Shell completions: `eval "$(openkey completion zsh)"` (also `bash` / `fish`). +Shell completion is available for Bash, Zsh, and Fish: + +```bash +eval "$(openkey completion zsh)" +``` -## Android (Termux) +## Android / Termux setup -Unlock OpenKey → **Settings → Data → Termux / CLI**, then: +If you use the OpenKey Android app, unlock it and open the relevant terminal configuration screen, then: ```bash pkg install nodejs npm install -g openkey-cli -export OPENKEY_NATIVE_PORT=... # from the sheet -export OPENKEY_NATIVE_TOKEN=... # from the sheet +export OPENKEY_NATIVE_PORT=... +export OPENKEY_NATIVE_TOKEN=... openkey status ``` -Port and token last only for that unlock. Copy them again after you lock the vault. +The port and token are short-lived and are generated for the current unlocked session. Re-copy them after locking the vault again. -## Optional: self-hosted server +## Optional: self-hosted server mode + +This mode uses a self-hosted OpenKey server for encrypted sync and session-based access. ```bash openkey config set-server http://localhost:8000 openkey login --email you@example.com -eval $(openkey unlock) +eval "$(openkey unlock)" +openkey sync +eval "$(openkey lock)" +``` + +Notes: + +- the master password is entered interactively, or provided via `OPENKEY_PASSWORD` in scripts/CI +- the email can also be supplied through `OPENKEY_EMAIL` +- the password must never be passed as a CLI flag + +## Backends and access model + +OpenKey CLI supports two primary backends. + +1. Native bridge + - uses an unlocked OpenKey desktop app or Android app locally + - this is the default path for vault-backed commands + - works for secrets, logins, cards, crypto wallets, password generation, and discovery + +2. CLI session + - obtained with `openkey login` + `openkey unlock` + - exports `OPENKEY_SESSION` for the current shell + - allows CLI commands to operate without the local desktop app being open + +`openkey gen` works without either backend because it generates passwords locally and does not access the vault. + +The config file is stored in the standard user config directory: + +- macOS: `~/Library/Application Support/OpenKey/config.json` +- Linux: `~/.config/openkey/config.json` +- Windows: `%APPDATA%\OpenKey\config.json` + +## Command reference + +The sections below describe the most important commands in detail. + +### 1) Password generation + +#### `openkey gen` + +Generate a password completely offline. This command does not require login, app unlock, or a server connection. + +Common options: + +```bash +openkey gen --help +openkey gen -l 24 +openkey gen -l 32 --no-symbols +openkey gen -l 20 --no-upper --no-digits +openkey gen -l 28 -a -c +``` + +What it does: + +- creates a secure password of the requested length +- supports uppercase, lowercase, digits, and symbols toggles +- can avoid ambiguous characters such as `I`, `l`, `1`, `O`, `0` +- can copy the result to your clipboard with `-c` + +Use this when you need a new strong password for a service or for testing local credentials without touching any vault state. + +### 2) Discovering secrets on-device + +#### `openkey discover` + +Search the current machine for likely secrets and import them into the OpenKey vault under a device collection. + +Examples: + +```bash +openkey discover --dry-run +openkey discover -d laptop --depth 5 +openkey discover --no-ssh --no-aws -y +``` + +This command can scan: + +- SSH keys and config +- `.env` files +- exported environment variables +- AWS config/credentials +- GitHub CLI token data +- Docker registry auth + +Flags: + +- `-d, --device`: choose the target device collection name +- `-p, --path`: scan specific directories +- `--depth`: max directory recursion depth for `.env` discovery +- `--dry-run`: show candidates without saving them +- `-y, --yes`: save new findings without prompting + +Use this to quickly onboard secrets into a structured, device-based vault instead of manually adding each item. + +### 3) Managing developer secrets + +OpenKey stores secret entries in device collections and allows typed secret kinds. + +#### Secret kinds + +- `apiToken` (default) +- `sshKey` +- `envSnippet` +- `other` + +#### `openkey secret add` + +Create a new secret object. + +```bash +openkey secret add --name "GitHub PAT" --kind apiToken --secret ghp_... +openkey secret add -n "SSH key" -k sshKey --file ~/.ssh/id_ed25519 +openkey secret add -n "My token" --stdin --secret - +``` + +Useful options: + +- `-n, --name`: display name +- `-k, --kind`: secret type +- `-s, --secret`: raw value +- `-f, --file`: read a value from a file +- `--stdin`: read from stdin +- `-u, --username`: related username +- `-H, --host`: hostname or service target +- `-d, --device`: assign a device collection +- `--public-key`, `--public-key-file`: SSH-related metadata +- `--notes`: description notes + +#### `openkey secret set` + +Create or update a secret matched by the combination of name and device. + +```bash +openkey secret set -n "GitHub PAT" -k apiToken -s ghp_... +``` + +This is useful when you want to upsert a secret without worrying whether the item already exists. + +#### `openkey secret list` + +List all secrets with masked values. + +```bash +openkey secret list +openkey secret list -d laptop +openkey secret list -k apiToken +``` + +This is safe for inspection because secret values are masked rather than printed in full. + +#### `openkey secret get` + +Print the raw secret value for a matched item. + +```bash +openkey secret get "GitHub PAT" +``` + +Use this when you need the actual credential value in a script or terminal. Because it prints the plaintext secret, use it deliberately. + +#### `openkey secret copy` + +Copy a secret directly to the system clipboard. + +```bash +openkey secret copy "GitHub PAT" +openkey secret copy "GitHub PAT" --clear 120 +openkey secret copy "GitHub PAT" --keep +``` + +The clipboard auto-clears after 45 seconds by default unless you disable that behavior with `--keep`. + +#### `openkey secret update` + +Modify fields on an existing secret without recreating it. + +```bash +openkey secret update "GitHub PAT" --secret ghp_newvalue +openkey secret update "GitHub PAT" --notes "Rotated on 2026-10-29" +``` + +#### `openkey secret export` + +Export secrets in a format ready for shell use. + +```bash +openkey secret export -d laptop -o .env.local +openkey secret export --format exports +``` + +This creates either a `.env`-style file or shell-export format, depending on the selected mode. + +#### `openkey secret devices` + +List device collections and the number of secrets assigned to each one. + +```bash +openkey secret devices +``` + +#### `openkey secret rm` + +Delete a secret. + +```bash +openkey secret rm "GitHub PAT" -y +``` + +This command prompts by default unless `-y` is used. + +### 4) Working with logins, cards, and crypto items + +In addition to typed secrets, OpenKey CLI can query other item categories already present in the vault. + +#### `openkey logins` + +List login entries with masked passwords. + +#### `openkey cards` + +List payment cards with numbers masked. + +#### `openkey crypto` + +List crypto wallets with masked keys or seed material. + +#### `openkey search` + +Search across secrets, logins, cards, and crypto items using a keyword query. + +```bash +openkey search api +openkey search github +``` + +#### `openkey get` + +Retrieve a value from a matching item when the item is not a plain secret. + +```bash +openkey get "GitHub" --field username +``` + +This is the general-purpose “fetch a known field from a credential item” command. + +#### `openkey totp` + +Generate a time-based one-time password for a matching login or secret record. + +```bash +openkey totp "GitHub" +openkey totp "GitHub" -c +``` + +Use `-c` to copy the TOTP code to the clipboard. + +### 5) Exporting values into shell commands + +#### `openkey env` + +Print environment-export statements for one or more vault items. + +```bash +eval "$(openkey env DATABASE_URL GITHUB_TOKEN)" +openkey env DATABASE_URL +openkey env DATABASE_URL=GitHub +``` + +This is intended for shell workflows where you want to inject secrets into your current session. + +#### `openkey run` + +Run a child process with selected secret values injected into its environment. + +```bash +openkey run -e DATABASE_URL -e GH=GitHub -- npm start +``` + +The command after `--` receives the environment variables you configured and runs normally. + +### 6) Server / session commands + +These commands are used for self-hosted server mode. + +#### `openkey login` + +Log in to the configured self-hosted server. + +```bash +openkey login --email you@example.com +``` + +#### `openkey logout` + +Clear server access tokens. + +#### `openkey unlock` + +Unlock the server-backed vault and print a shell-ready `OPENKEY_SESSION` export. + +```bash +eval "$(openkey unlock)" +``` + +#### `openkey lock` + +Print the command to clear the active `OPENKEY_SESSION`. + +#### `openkey sync` + +Pull ciphertext from the server and optionally push the local cache. + +```bash openkey sync -eval $(openkey lock) +openkey sync --push ``` -Master password: interactive prompt, or `OPENKEY_PASSWORD` for scripts/CI (never a CLI flag). Email can come from `OPENKEY_EMAIL`. +#### `openkey config set-server` -## Commands (summary) +Set the OpenKey server URL. -| Command | Vault access? | Description | -|---------|---------------|-------------| -| `gen` | No | Offline password generation (`-l`, `--no-*`, `-a`, `-c`) | -| `discover` | Save: yes\* | Scan SSH / `.env` / env / AWS → device group | -| `secret add\|list\|get\|copy\|rm\|update\|export\|devices\|set` | Yes\* | Typed developer secrets (`--stdin` / `--secret -`) | -| `get` / `copy` / `search` / `totp` / `logins` / `cards` / `crypto` | Yes\* | Secrets + logins + cards + wallets | -| `env` / `run` | Yes\* | Export secrets into the shell or a child process | -| `doctor` | No | Diagnose bridge / session / server / clipboard | -| `completion` | No | Bash / zsh / fish completion scripts | -| `status` / `config` / `forget` | No | Diagnostics and local state | -| `login` / `logout` / `unlock` / `lock` / `sync` | Server path | Optional ciphertext sync + session (`sync --push`) | +```bash +openkey config set-server http://localhost:8000 +``` -\*Desktop or Android app unlocked, **or** `eval $(openkey unlock)` after `login`. +#### `openkey config show` -Global: `--json` for machine-readable output. +Display the current CLI configuration. -Clipboard copies auto-clear after **45s** by default (`--keep` to disable; `--clear N` to change). +#### `openkey config set-lock` -### Secret kinds +Set the unlock session lifetime in minutes. -`apiToken` (default), `sshKey`, `envSnippet`, `other` — see the [CLI guide](../openkey_docs/guide/cli.md) for flags (`--file`, `--public-key-file`, `--device`, …). +### 7) Diagnostics and utilities -## Backends +#### `openkey status` -1. **Native bridge** — unlocked desktop (or Android Termux) app (default). -2. **CLI session** — `OPENKEY_SESSION` after `unlock`. +Show the current status of the local bridge, running session, and server connection. -`openkey gen` needs neither. +#### `openkey doctor` -Config file (mode `600` when supported): macOS `~/Library/Application Support/OpenKey/config.json`, Linux `~/.config/openkey/config.json`, Windows `%APPDATA%\OpenKey\config.json`. +Run a focused diagnosis of CLI, bridge, session, and server health. + +```bash +openkey doctor +``` + +#### `openkey completion` + +Print a shell completion script. + +```bash +openkey completion bash +openkey completion zsh +openkey completion fish +``` + +#### `openkey forget` + +Wipe local config and cached ciphertext from the CLI. + +## Global behavior + +- `--json` makes output machine-readable +- clipboard copies are cleared automatically after 45 seconds by default +- use `--keep` if you want the copied value to remain in the clipboard +- `--clear N` changes the clipboard timeout in seconds + +## Security notes + +- `list` and `search` mask secret values; use `get` or `copy` when you need the plaintext +- never pass the master password as a CLI flag +- session lifetimes default to a limited window and can be set with `openkey config set-lock` +- bridge access is local-only while the vault remains unlocked +- server mode stores ciphertext; the real key material remains client-side ## Development @@ -132,14 +507,6 @@ npm run typecheck npm run build ``` -## Security notes - -- `list` / `search` mask values; use `get` / `copy` for plaintext -- Do not pass the master password as a CLI flag -- Sessions expire (default 15 minutes; `config set-lock`) -- Bridge is local-only while the vault is unlocked -- Server stores ciphertext only; keys are derived on the client - ## License OpenKey CLI is licensed under the [MIT License](./LICENSE). From a1b19ddf45c2680cf57c7939d66d7f016cd7f6bc Mon Sep 17 00:00:00 2001 From: Asim Awdah Date: Thu, 29 Oct 2026 22:39:48 +0300 Subject: [PATCH 2/3] docs: update README for improved clarity and structure; enhance usage examples and add installation image --- .github/assets/openkey-cli-install.png | Bin 0 -> 7784 bytes README.md | 100 +++++++++++++++++++++---- 2 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 .github/assets/openkey-cli-install.png diff --git a/.github/assets/openkey-cli-install.png b/.github/assets/openkey-cli-install.png new file mode 100644 index 0000000000000000000000000000000000000000..0e96e0325cad5f6abcc3f289efaaf4215c3a8173 GIT binary patch literal 7784 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 + OpenKey CLI install command +

+ # OpenKey CLI OpenKey CLI is the command-line companion for the self-hosted, end-to-end encrypted [OpenKey](https://github.com/OpenSelfHosting/OpenKey) password manager. -It lets you: +It helps you: + +- generate strong passwords entirely offline +- manage secrets, logins, cards, and crypto records from a local unlocked OpenKey app +- discover SSH keys, `.env` files, API tokens, AWS credentials, and other likely leaks on your machine +- export selected values into your shell or a child process +- sync encrypted data with a self-hosted OpenKey server when you want server-backed access + +This README is a practical quick-start guide. For deeper product docs and platform setup notes, see the [CLI guide](https://openkey.openselfhosting.com/guide/cli). -- generate secure passwords offline -- manage developer secrets from an unlocked OpenKey desktop or Android app -- discover SSH keys, `.env` files, API tokens, AWS credentials, and other sensitive material -- export selected values into your shell or child processes -- optionally sync encrypted data with a self-hosted OpenKey server +## Why use OpenKey CLI? -Full documentation: [CLI guide](https://openkey.openselfhosting.com/guide/cli). +OpenKey CLI is designed for developers who want a fast, local-first workflow without uploading secrets to a third-party service. + +Typical use cases: + +- generate and rotate app passwords without leaving the terminal +- keep API tokens, SSH keys, and `.env` values in a structured vault +- retrieve a secret for a single command or shell session without exposing it in your shell history +- discover secrets already sitting on disk and bring them under versioned vault control +- operate in a self-hosted setup where the server only stores encrypted payloads ## Requirements @@ -27,10 +43,19 @@ npm install -g openkey-cli openkey --version ``` +### Run without installing globally + +```bash +npx openkey-cli --help +npx tsx src/cli.ts --help +node dist/cli.js --help +``` + ### From source ```bash -cd openkey_cli +git clone https://github.com/OpenSelfHosting/OpenKey_cli.git +cd OpenKey_cli npm install npm run build npm link @@ -38,12 +63,39 @@ npm link `npm link` is optional, but it makes the `openkey` binary available globally on your PATH. -### Run without linking +## Common workflows + +A good default workflow looks like this: ```bash -npx openkey-cli --help -npx tsx src/cli.ts --help -node dist/cli.js --help +# 1) check whether a local bridge or server session is available +openkey status + +# 2) generate a password without touching your vault +openkey gen -l 24 --no-symbols + +# 3) scan for likely secrets and review the results +openkey discover --dry-run + +# 4) save approved findings into a device collection +openkey discover -y + +# 5) list or fetch the values you need +openkey secret list +openkey get "GitHub" --field username +openkey secret copy "GitHub PAT" + +# 6) export selected values for the current shell session +eval "$(openkey env DATABASE_URL GITHUB_TOKEN)" +``` + +OpenKey CLI also supports a server-backed flow for self-hosted deployments: + +```bash +openkey config set-server http://localhost:8000 +openkey login --email you@example.com +eval "$(openkey unlock)" +openkey sync ``` ## Quick start @@ -157,7 +209,18 @@ The config file is stored in the standard user config directory: ## Command reference -The sections below describe the most important commands in detail. +These are the commands most people use day to day. + +### At a glance + +- `openkey gen` — generate a strong password offline +- `openkey discover` — scan a machine for likely secrets and onboard them +- `openkey secret ...` — add, list, get, update, and export secrets +- `openkey logins`, `openkey cards`, `openkey crypto` — inspect non-secret vault records +- `openkey get`, `openkey copy`, `openkey totp` — fetch values for a single item +- `openkey env` / `openkey run` — inject values into shells or child processes +- `openkey sync`, `openkey login`, `openkey unlock` — use self-hosted server mode +- `openkey doctor` — check local bridge/session/server health ### 1) Password generation @@ -283,6 +346,17 @@ openkey secret get "GitHub PAT" Use this when you need the actual credential value in a script or terminal. Because it prints the plaintext secret, use it deliberately. +#### `openkey copy` + +Copy a best-match vault item by name, host, or UUID prefix without requiring the `secret` subcommand. This is the shorthand for the common “copy a secret to clipboard” workflow. + +```bash +openkey copy "GitHub PAT" +openkey copy "GitHub" --clear 60 +``` + +When the item is not a secret, OpenKey copies the matched value in the same way the generic `get` command resolves it. + #### `openkey secret copy` Copy a secret directly to the system clipboard. From 3cec10f8741db0d3712eb1543ef7790de4a60c11 Mon Sep 17 00:00:00 2001 From: Asim Awdah Date: Thu, 29 Oct 2026 23:07:26 +0300 Subject: [PATCH 3/3] test: align API tests with canonical unversioned routes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/commands/auth.test.ts | 18 +++++++++--------- src/lib/api.test.ts | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/commands/auth.test.ts b/src/commands/auth.test.ts index 10a494b..9cf6485 100644 --- a/src/commands/auth.test.ts +++ b/src/commands/auth.test.ts @@ -64,13 +64,13 @@ describe("cmdUnlock", () => { const requestedPaths: string[] = []; const server = createServer(async (request, response) => { requestedPaths.push(request.url ?? ""); - if (request.method === "POST" && request.url === "/api/v1/auth/prelogin") { + if (request.method === "POST" && request.url === "/auth/prelogin") { await readJson(request); respond(response, { salt: toB64Url(salt), kdf_params: serverKdfParams, }); - } else if (request.method === "POST" && request.url === "/api/v1/auth/login") { + } else if (request.method === "POST" && request.url === "/auth/login") { const body = await readJson(request); expect(body.auth_hash).toBe(deriveAuthHash(masterKey)); respond(response, { @@ -78,14 +78,14 @@ describe("cmdUnlock", () => { refresh_token: "test-refresh", user_id: "user-id", }); - } else if (request.method === "GET" && request.url === "/api/v1/auth/me") { + } else if (request.method === "GET" && request.url === "/auth/me") { respond(response, { email, salt: toB64Url(salt), kdf_params: serverKdfParams, encrypted_vault_key: wrapped, }); - } else if (request.method === "POST" && request.url === "/api/v1/sync") { + } else if (request.method === "POST" && request.url === "/sync") { respond(response, { entries: [], collections: [], @@ -119,10 +119,10 @@ describe("cmdUnlock", () => { expect(log).toHaveBeenCalledOnce(); expect(requestedPaths).toEqual([ - "/api/v1/auth/prelogin", - "/api/v1/auth/login", - "/api/v1/auth/me", - "/api/v1/sync", + "/auth/prelogin", + "/auth/login", + "/auth/me", + "/sync", ]); } finally { process.env.XDG_CONFIG_HOME = previousEnv.XDG_CONFIG_HOME; @@ -133,5 +133,5 @@ describe("cmdUnlock", () => { ); await rm(configRoot, { recursive: true, force: true }); } - }); + }, 15_000); }); diff --git a/src/lib/api.test.ts b/src/lib/api.test.ts index fe7511d..19551a9 100644 --- a/src/lib/api.test.ts +++ b/src/lib/api.test.ts @@ -38,7 +38,7 @@ describe("server network errors", () => { "user@example.com", ), ).rejects.toThrow( - "Could not reach OpenKey server at https://server.example/api/v1/auth/prelogin: connect ECONNREFUSED (ECONNREFUSED)", + "Could not reach OpenKey server at https://server.example/auth/prelogin: connect ECONNREFUSED (ECONNREFUSED)", ); }); });