From 94b401e83729acdb1dd3372ef8bd79f12ad20c12 Mon Sep 17 00:00:00 2001 From: Nathan Schneider Date: Sun, 18 Oct 2026 23:28:49 -0600 Subject: [PATCH] README: per-member key auto-load section + redaction gotcha --- README.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/README.md b/README.md index 2283c76..4357980 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,45 @@ needed. `tinfoil/whisper-large-v3-turbo`, both via the gateway with the capped key. - **Web search**: SearXNG (self-hosted) + keyless Keenable scraper, no reranker. + +## Per-member key auto-load (no API-key prompts) + +Members never enter an API key. Chat and image generation resolve each +member's own portal-provisioned key automatically: + +1. The portal provisions a per-member LiteLLM key at onboarding and stores it + (`members.key_token`). +2. `GET /admin/librechat/keys` on the portal returns those keys for ACTIVE + members — authenticated by the dedicated `X-Sync-Token` header + (`LIBRECHAT_SYNC_TOKEN`, set on BOTH apps; not the admin token). +3. `sync-keys.js` (this repo, deployed to `/app/data/sync-keys.js`) fetches + that feed and upserts, per member with a sandbox account: + - `keys` collection: `{userId, name: "Inference Co-op", value: encrypt(JSON.stringify({apiKey}))}` + — consumed by the chat endpoint (`apiKey: "user_provided"` in the yaml). + - `pluginauths` collection: `{userId, pluginKey: "mcp:inference-image", + authField: "IC_API_KEY", value: encrypt(key)}` — consumed by the MCP + `customUserVars` config so image generation bills to the member's team. + Encryption uses LibreChat's own scheme (`CREDS_KEY`/`CREDS_IV`, AES-256-CBC + via `@librechat/data-schemas` `encrypt()`), read from the app process env + (`/proc/1/environ`) because `cloudron exec` sessions don't inherit it. +4. Members who haven't logged in to the sandbox yet are skipped; the next + run seeds them. Run hourly or nightly: + +```bash +cloudron --server my.inference.coop --token "$CLOUDRON_TOKEN" exec \ + --app 4023ccbf-d57a-4500-97df-14de9cf3516e \ + -- bash -c "cd /app/code/librechat/api && node /app/data/sync-keys.js" +``` + +Idempotent. Verify with the DB probe: `keys` and `pluginauths` counts should +equal the number of members who have logged in to the sandbox. + +> **Output-redaction gotcha:** terminal output renders values after +> `apiKey:` as `***` even when the file contains `user_provided` or +> `${ENV_REF}`. Never conclude a file contains a literal placeholder from +> redacted output — probe lengths/counts instead +> (`tr -cd '*' < file | wc -c`, `awk -F'apiKey: ' '{print length($2)}'`). + ## Known state / limitations - The `[schedules]` Redis guard error is resolved by