-
Notifications
You must be signed in to change notification settings - Fork 1k
Public Creds
Source of truth:
open-sse/utils/publicCreds.tsTests:tests/unit/publicCreds.test.tsLast updated: 2026-05-14 — v3.8.0 Audience: Engineers integrating providers that ship public OAuth client_id / client_secret / Firebase Web API keys in their public CLIs. Status: MANDATORY for all new code that embeds upstream identifiers.
Some upstream providers (Gemini CLI, Antigravity CLI, Windsurf / Devin CLI, GitHub Copilot, and similar OAuth-native clients) ship credentials extracted from their public binaries or web apps. Google explicitly documents that these are not secrets:
- OAuth 2.0 for native apps (PKCE) — OAuth client_id / client_secret for installed apps are public; PKCE provides the actual security.
- Firebase API keys — Web client identifiers are public by design.
OmniRoute must embed these values so users who do not configure .env still get a working OAuth flow out of the box. Without an embedded fallback, the Gemini / Antigravity / Windsurf providers stop working for any user who follows the "just clone and run" path.
However, literal values like AIzaSy…, GOCSPX-…, …apps.googleusercontent.com are matched by GitHub Secret Scanning, Semgrep, and similar pattern scanners. Every release becomes a noisy stream of false positives, push protection blocks legitimate commits, and operators stop trusting the alert feed.
The open-sse/utils/publicCreds.ts helper solves both constraints at once:
- Embeds the public identifier as a XOR-masked byte sequence (no scanner pattern in source).
- Decodes at runtime via
decodePublicCred/resolvePublicCred. - Detects raw values that already follow well-known prefixes (
AIza,GOCSPX-,<digits>-<32hex>.apps.googleusercontent.com,Iv1.<hex>) and passes them through unchanged, so users with raw values in their existing.envkeep working with zero migration.
This is obfuscation, not encryption. Anyone reading the source can recover the value — which is fine because the value is public by design. The only goal is to avoid scanner regex matches.
When you need to embed a new upstream-provided value that:
- comes from a public CLI / desktop app / browser bundle, and
- the upstream provider documents (or treats) it as a public client identifier, and
- a pattern scanner would otherwise match it (
AIza…,GOCSPX-…,<digits>-…apps.googleusercontent.com, etc.),
…follow this checklist:
-
Generate the masked byte sequence:
node --import tsx/esm -e \ 'import("./open-sse/utils/publicCreds.ts").then(m => console.log(JSON.stringify(Array.from( Buffer.from(m.encodePublicCred("THE_PUBLIC_VALUE"), "base64") ))))'
-
Add a new entry to
EMBEDDED_DEFAULTSinopen-sse/utils/publicCreds.tswith a neutral key name (<provider>_id,<provider>_alt,<provider>_fb, etc.). Do not use names likeclient_secretorapi_keyin the helper — those words trigger Semgrep generic-secret rules. -
Add a
keyof typeof EMBEDDED_DEFAULTSto the public type union (it is inferred automatically). -
In the consumer code, replace the hardcoded literal with:
// single env override clientSecret: resolvePublicCred("provider_alt", "PROVIDER_OAUTH_CLIENT_SECRET"), // multiple env aliases (first non-empty wins) clientId: resolvePublicCredMulti("provider_id", [ "PROVIDER_CLI_OAUTH_CLIENT_ID", "PROVIDER_OAUTH_CLIENT_ID", ]), // no env override (always embedded default) firebaseApiKey: resolvePublicCred("provider_fb"),
-
Remove the literal from
.env.example(replace with comment-only documentation pointing readers here):# ── Provider (Google / Firebase / etc.) ── # Public OAuth credentials are baked into the code via # open-sse/utils/publicCreds.ts. Set these vars only to use your own. # PROVIDER_OAUTH_CLIENT_ID= # PROVIDER_OAUTH_CLIENT_SECRET=
-
Update
tests/unit/publicCreds.test.tsto add a shape assertion for the new key (verify format, not literal value — see existing tests for the pattern). -
Never add
AIza…/GOCSPX-…/…apps.googleusercontent.comliterals to test files. Use theFAKE_*constants built from.join("")fragments (see existing tests).
-
Read from
resolvePublicCred()/resolvePublicCredMulti()only — never calldecodePublicCredBytes()directly outside the helper. - The helper is intentionally cheap (linear byte XOR) and safe to call at module-load time; defaults are computed once.
- The env override always wins. If a user sets
PROVIDER_OAUTH_CLIENT_SECRET=GOCSPX-myown, the helper passes that raw value straight through.
❌ Never do any of the following in production code (src/, open-sse/, electron/, bin/):
// BAD: literal value triggers Secret Scanning + Semgrep
clientSecret: process.env.PROVIDER_OAUTH_CLIENT_SECRET || "GOCSPX-realvalue",
// BAD: base64 of the literal — GitHub still detects since Feb/2025
clientSecret: process.env.PROVIDER_OAUTH_CLIENT_SECRET ||
Buffer.from("R09DU1BYLXJlYWx2YWx1ZQ==", "base64").toString(),
// BAD: string concatenation that re-assembles the pattern at runtime
clientSecret: "GO" + "CS" + "PX-" + "realvalue",
// BAD: hex/ROT13 encoding — different obfuscation, same risk of detection
clientSecret: hexDecode("474f4353..."),These all eventually trip a scanner. Use resolvePublicCred().
❌ Never add literal credentials to .env.example. Users who need real upstream values can extract them from the public CLI themselves, or use their own OAuth registration.
❌ Never dismiss a new secret-scanning alert without first checking whether the credential should be moved to this helper.
-
RAW_VALUE_PATTERNinpublicCreds.tsenumerates the prefixes that trigger passthrough (retrocompat). Extend it only for documented public credential formats, never for proprietary secrets. -
.env.examplelives in CI'scheck-env-doc-syncscript — when you remove a var here, make sure the docs match. - The
npm run test:vitestandnode --import tsx/esm --test tests/unit/publicCreds.test.tssuites must both stay green.
This helper is only for credentials that are:
- Distributed publicly by the upstream provider (CLI binary, browser bundle, official docs).
- Documented or strongly implied to be non-confidential (PKCE-protected, Firebase Web key, similar).
For everything else — operator-issued tokens, per-tenant secrets, your own OAuth app's client_secret, encryption keys, JWT secrets, database passwords — use env vars only (process.env.FOO, || fallback to empty / explicit error). These belong in .env and the encrypted credentials store, not in source.
- Google: OAuth 2.0 for native apps
- Firebase: API keys for client identification
- GitHub Secret Scanning supported secrets
- GitHub: base64 detection for tokens (Feb 2025)
- Commit introducing this helper:
1a39c31f— fix(security): mask public upstream creds + centralize error sanitization
OmniRoute · Website · npm · Docker Hub
- Setup Guide
- User Guide
- Features
- Quick Start (Docker)
- Electron Desktop App
- Termux (Android)
- PWA Guide
- MCP Server
- A2A Server
- Agent Protocols
- OpenCode Plugin
- Webhooks
- Cloud Agents
- Skills
- Memory
- Evals
- Gamification
- Guardrails
- Compliance
- Error Sanitization
- Public Credentials
- Route Guard Tiers
- Stealth Guide
- CLI Token Auth