Skip to content

Add API key gate modal for browser-based key input - #136

Open
EnchantedBroccoliForest wants to merge 2 commits into
mainfrom
claude/busy-hamilton-p77PS
Open

Add API key gate modal for browser-based key input#136
EnchantedBroccoliForest wants to merge 2 commits into
mainfrom
claude/busy-hamilton-p77PS

Conversation

@EnchantedBroccoliForest

Copy link
Copy Markdown
Owner

Summary

Replaces environment variable-based API key configuration with a browser UI modal that prompts users to enter their OpenRouter API key at runtime. Keys are held in memory only and never persisted to disk, localStorage, or cookies, clearing on page refresh.

Key Changes

  • New ApiKeyGate component (src/components/ApiKeyGate.jsx): A blocking modal dialog that appears when no API key is present. Validates key format (sk-or- prefix) and includes an optional collapsible section for xAPI (X/Twitter enrichment) keys.

  • In-memory key storage: Refactored src/api/openrouter.js and src/pipeline/xapi.js to store user-supplied keys in module-level variables (_userApiKey, _userXapiKey) instead of reading from environment variables at build time. Eliminates the risk of accidentally embedding keys in the public bundle.

  • New useApiKey hook (src/hooks/useApiKey.js): Exposes hasKey, setKey, and clearKey via useSyncExternalStore, allowing React components to subscribe to key state changes without exposing the actual key value to devtools.

  • Removed VITE_ prefixed env vars: Stripped VITE_OPENROUTER_API_KEY, VITE_OPENAI_API_KEY, and VITE_XAPI_KEY fallbacks from browser code. Node-only paths (CLI, eval harness, HTTP service) now read only OPENROUTER_API_KEY and XAPI_KEY from process.env.

  • Updated i18n strings: Added 10 new translation keys for the API key gate UI (title, body, placeholder, error messages, xAPI toggle, notice) in both English and Chinese.

  • Updated CLI/service docs: Simplified environment variable documentation in bin/pm-tools.js and bin/pm-tools-service.js to reflect the single OPENROUTER_API_KEY requirement for Node environments.

  • Styling: Added ~150 lines of CSS for the modal backdrop, panel, form inputs, error states, and collapsible details section with smooth transitions.

Implementation Details

  • Keys are validated on form submission; empty or malformed keys trigger inline error messages.
  • The modal is non-dismissible (no close button) until a valid key is entered, ensuring the app cannot proceed without one.
  • xAPI key is optional and hidden behind a disclosure to reduce cognitive load for users who don't need X/Twitter enrichment.
  • Browser detection (isBrowser()) ensures Node code paths never attempt to read import.meta.env, preventing accidental key leakage into bundles.
  • Subscription mechanism allows multiple listeners (e.g., different hooks) to react to key changes without tight coupling.

https://claude.ai/code/session_01Lpf6vXKUaJp51385XZzWZz

claude added 2 commits May 23, 2026 12:02
…upplied key

Vite inlines any VITE_-prefixed env var into the production bundle, so the
public site at 42creator.space was shipping the contents of VITE_OPENAI_API_KEY
in plain text. Drop all VITE_ key references from the browser path and have
users paste their own OpenRouter key into a blocking gate at load time. The
key is held only in module-level memory in src/api/openrouter.js — never
written to localStorage, cookies, or any other persistence — so a refresh
clears it. CLI / HTTP service paths keep reading OPENROUTER_API_KEY from
process.env (no VITE_ fallback), and the README is updated to match.
Same fix as the OpenRouter key: stop reading VITE_-prefixed env vars in the
browser path so Vite cannot inline an xAPI key into the public bundle. The
key is now supplied through an optional, collapsed disclosure inside the
existing ApiKeyGate modal and held only in module-level memory in
src/pipeline/xapi.js. Node (CLI / eval / HTTP service) still reads
process.env.XAPI_KEY and ~/.xapi/config.json as before.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants