Public Credentials Handling
Source of truth:
open-sse/utils/publicCreds.tsTests:tests/unit/publicCreds.test.tsLast updated: 2026-08-07 — v3.8.50 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.
Why this exists
Section titled “Why this exists”- 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 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.
The mandatory pattern
Section titled “The mandatory pattern”1. Adding a new public credential
Section titled “1. Adding a new public credential”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:
Terminal window 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 overrideclientSecret: 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).
2. Consumers
Section titled “2. Consumers”- 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.
3. Forbidden patterns
Section titled “3. Forbidden patterns”❌ Never do any of the following in production code (src/, open-sse/, electron/, bin/):
// BAD: literal value triggers Secret Scanning + SemgrepclientSecret: process.env.PROVIDER_OAUTH_CLIENT_SECRET || "GOCSPX-realvalue",
// BAD: base64 of the literal — GitHub still detects since Feb/2025clientSecret: process.env.PROVIDER_OAUTH_CLIENT_SECRET || Buffer.from("R09DU1BYLXJlYWx2YWx1ZQ==", "base64").toString(),
// BAD: string concatenation that re-assembles the pattern at runtimeclientSecret: "GO" + "CS" + "PX-" + "realvalue",
// BAD: hex/ROT13 encoding — different obfuscation, same risk of detectionclientSecret: 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.
Related controls
Section titled “Related controls”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.
When NOT to use this helper
Section titled “When NOT to use this helper”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.
References
Section titled “References”- 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
HagiCode
HagiCode is an agentic coding workspace: structured workflows, multi-agent execution, and Hero Dungeon views turn ideas into shipped software.
Turn ideas into polished, usable software with a smarter, faster, and more enjoyable agentic coding workflow.

- SmartStructured workflows turn intent into an executable path from idea to shipped change.
- EfficientMulti-agent workflows keep research, implementation, and review moving in parallel.
- FunHero Dungeon interfaces make long coding sessions visual, collaborative, and rewarding.