Bring your own key
By default, turning on end-to-end encryption mints the 32-byte channel key on your iPhone or Mac. That’s the low-friction path — but it means the app generated the key for you. If you’d rather not take our word for the generator, bring your own key: create it yourself on the machine where your agent runs, and the Pidge app only ever receives it.
What this buys you:
- The key is born outside Pidge’s code. No claim about our random-number generator to trust — you ran the generator.
- The secret never transits anything. With a minted key, the app hands
PIDGE_SECRETto the agent’s machine via an AirDropped terminal command. With your own key, the secret is already on that machine the moment it exists — the only thing that travels is the key you paste into the app, from your terminal to your Keychain. - You can verify, end to end. You know the key, so you can check every link in the chain (below).
Create the key
Section titled “Create the key”Run this on the machine where your agent runs, as the user the agent runs as (and with the
same PIDGE_AGENT set, if you use one). It needs openssl, which macOS and virtually every
Linux ship with:
sh -c 'umask 077; k=$(openssl rand -base64 32 | tr "+/" "-_" | tr -d "="); [ ${#k} -eq 43 ] || { echo "key generation FAILED — is openssl installed?" >&2; exit 1; }; a=$(printf %s "$PIDGE_AGENT" | sed "s/^[[:space:]]*//;s/[[:space:]]*$//" | tr -c "A-Za-z0-9_.-" "_" | cut -c1-64); d="${XDG_CONFIG_HOME:-$HOME/.config}/pidge${a:+/agents/$a}"; mkdir -p "$d"; chmod 700 "$d"; f="$d/env"; touch "$f"; chmod 600 "$f"; grep -v "^PIDGE_SECRET=" "$f" > "$f.tmp"; printf "PIDGE_SECRET=%s\n" "$k" >> "$f.tmp"; chmod 600 "$f.tmp"; mv "$f.tmp" "$f"; echo "PIDGE_SECRET saved to $f"; echo; echo "Your key — paste it into the Pidge app:"; echo "$k"'One command, three effects:
- Generates 32 random bytes with your machine’s CSPRNG (
openssl rand) and encodes them as 43 base64url characters — the exact wire form Pidge uses everywhere. - Installs the key as
PIDGE_SECRETin the CLI’s config file (~/.config/pidge[/agents/<id>]/env, permissions600), exactly wheresetup --claimkeeps the channel token. It’s idempotent: re-running replaces the oldPIDGE_SECRETline and touches nothing else. If yoursetupstored the token in a project scope (pidge-cli ≥ 0.43, inside a git repo), runnpx pidge-cli doctorafterwards — it prints the config path in use and validates the secret; if it doesn’t seePIDGE_SECRET, move that one line into the file doctor names. - Prints the key, once, for the one manual step left: entering it in the app.
Enter it in the app
Section titled “Enter it in the app”In the Pidge app: channel → End-to-end encryption → turn the toggle on → Use My Own
Key… → paste the printed key. The app validates it (43 base64url characters, exactly 32
bytes — the same string must work verbatim as PIDGE_SECRET) and shows its fingerprint.
The option only appears while the channel has no key yet. A channel that already has one (minted earlier, or synced in from another device via iCloud Keychain) won’t offer it — swapping keys under an agent and an encrypted history is exactly the foot-gun this guards.
Verify the chain
Section titled “Verify the chain”- Same key on both ends: run
npx pidge-cli doctoron the agent’s machine. It validates the secret and prints its fingerprint — it must match the one the app showed when you pasted the key. The channel’s connect screen keeps showing that fingerprint. - The server only has ciphertext: fetch any sealed notification straight from the API
(
GET /api/v1/notifications/<cid>with the channel key) — the content fields arev1:AES-256-GCM envelopes. You hold the key and the format is documented, with committed test vectors in the open CLI — nothing stops you from decrypting an envelope yourself, outside any Pidge code.
Handle it like the password it is
Section titled “Handle it like the password it is”- One key per channel. Don’t reuse it across channels or anywhere else.
- Keep it out of chats. The agent’s chat log syncs to the provider’s cloud — that’s why the setup prompt never carries the secret, and yours shouldn’t either. Terminal and app only. Storing it in a password manager is fine.
- It doesn’t expire and there’s no server recovery. Lose the key (and the iCloud Keychain copy) and the encrypted history is unreadable, permanently.
- The generated key lands in your terminal scrollback once — clear it if the machine is shared. (It deliberately never enters shell history: the command stores it in a variable, not in your prompt line.)
Honest scope
Section titled “Honest scope”Bring-your-own-key removes one trust assumption — that Pidge’s key generation is honest. The remaining one is the same as for any end-to-end encrypted app: the client you run must not leak the key it holds. See the security model for the full threat model.
