Skip to content

Store secrets in the OS keychain

A regular env variable lives in plain text inside envs/<env>.toml. That’s fine for BASE_URL, but not for PAYMENTS_API_TOKEN or your Postgres password. Marking a variable as secret changes where it’s stored: OS keychain (Keychain on macOS, Credential Manager on Windows, Secret Service on Linux), with only a sentinel value in the TOML / SQLite.

In the Environment manager (sidebar LuLayers icon → pick env → click a variable row):

  1. Click the 🔒 lock toggle next to the value field.
  2. The first time, httui prompts: “Enter the secret value for PAYMENTS_API_TOKEN. Type the real value, hit Enter.
  3. httui stores the value in your OS keychain and writes the sentinel __KEYCHAIN__ to envs/<env>.toml / SQLite.

The TOML now looks like:

envs/staging.toml
[vars]
BASE_URL = "https://staging-api.example.com"
PAYMENTS_API_TOKEN = "__KEYCHAIN__" # real value in keychain

You can safely commit this file — the actual token never touches git.

Reference the secret like any other variable

Section titled “Reference the secret like any other variable”

Same {{KEY}} syntax:

```http
GET {{BASE_URL}}/payments
Authorization: Bearer {{PAYMENTS_API_TOKEN}}
```

At run time, httui:

  1. Sees the reference, looks up PAYMENTS_API_TOKEN.
  2. Finds the sentinel __KEYCHAIN__.
  3. Fetches the real value from the OS keychain.
  4. Substitutes and sends the request.

The Raw tab in the response panel does NOT show the resolved secret — it’s masked as *** so screen recordings stay safe.

Same flow for connections.toml. When you add a Postgres connection:

[connections.pg-staging]
type = "postgres"
host = "pg-staging.acme.local"
port = 5432
database = "payments"
user = "{{keychain:pg-staging:user}}"
password = "{{keychain:pg-staging:password}}"
ssl_mode = "require"

The {{keychain:<scope>:<key>}} syntax tells httui “look this up in the keychain under <scope> namespace”. The first time a block uses this connection, httui prompts for the values and stores them.

Sharing connections without sharing secrets

Section titled “Sharing connections without sharing secrets”

The connections.toml above commits cleanly — host, port, database, user/password as references. Your teammate clones the vault, opens it, and httui sees the references but no keychain entries.

httui shows a “Resolve secrets” banner at the top of the editor:

⚠ This vault references 2 secrets not in your keychain: pg-staging:user, pg-staging:password. Resolve →

Click → prompt for each → keychain populated. Both machines now run the same runbook against the same connection, but each developer’s password stays on their own machine.

What happens if the keychain is locked / unavailable

Section titled “What happens if the keychain is locked / unavailable”
SituationBehavior
Keychain locked (macOS sleep / Linux not logged in)First block hits prompt for system password; subsequent blocks in same session reuse the unlocked keychain
Keychain entry missing”Resolve secrets” banner appears; block won’t run until populated
Keychain backend unavailable (CI runner, headless)httui falls back to plaintext value in TOML / SQLite, logs a warning

The fallback is intentional — you’d rather have a CI runbook run with secrets injected via env vars than fail because there’s no Keychain.app on the runner.

  1. Open Environment manager → pick the variable.
  2. Click the value field (still shows ***).
  3. Type the new value, hit Enter.
  4. httui overwrites the keychain entry. The sentinel in TOML doesn’t change.

All blocks that reference the variable use the new value on next run — caches keyed on the old value invalidate automatically (the cache key includes a fingerprint of resolved secrets).

In Environment manager, click the trash icon next to the variable row. httui:

  1. Removes the keychain entry.
  2. Removes the line from envs/<env>.toml / SQLite.

If a block still references the deleted key, the next run shows a “Resolve secrets” banner with the missing key listed.

SymptomCauseFix
Block sends Bearer __KEYCHAIN__ literallyKeychain entry missing; httui couldn’t resolveClick “Resolve secrets” in the banner
Secret value changed but block still uses old valueStale block cache (unlikely — cache invalidates on env change)Toolbar gear → “Clear cache”
Want to see the actual secret for debuggingThe UI masks values intentionallyOpen the OS keychain UI (Keychain Access / Credential Manager)