Fix guide · critical · oauth_client_secret_in_client

OAuth client_secret embedded in client bundle

What this rule means

An OAuth client_secret was found inside your deployed JavaScript. Anyone who views your bundle can now impersonate your application against the OAuth provider.

Why it matters

The client_secret is the credential your *backend* uses to prove to the OAuth provider that token-exchange requests genuinely come from your app. It is the OAuth equivalent of a server-side API key: never meant to leave your servers, never meant to be visible to a user, and absolutely never meant to be in a browser bundle.

Once it leaks:

This is a direct impersonation. It is not theoretical. Bots harvesting public bundles for OAuth secrets exist; the secret is compromised the moment the bundle ships.

The reason it ends up in the bundle: usually a copy-paste error from a tutorial that says "set CLIENT_ID and CLIENT_SECRET", and the developer prefixes both with NEXT_PUBLIC_ / VITE_ / PUBLIC_ because that's what made the build pipeline pick them up. The provider expects only CLIENT_ID to be public; CLIENT_SECRET belongs server-side only.

How to fix it

  1. Rotate the secret immediately at the OAuth provider's developer console. Treat the leaked one as fully compromised.
  2. Move OAuth code-exchange to your backend. The browser hands the auth code to your server; your server exchanges it for a token using the secret.
  3. Use the public client + PKCE pattern instead if you have no backend (SPAs, mobile apps). PKCE replaces the client_secret with a per-flow ephemeral hash. Every modern OAuth provider supports it.
  4. Audit your env-var prefixes. NEXT_PUBLIC_, VITE_, PUBLIC_, REACT_APP_ all inline values into the client bundle at build time. Anything secret must NOT have those prefixes.
  5. Add a CI gate: vibecheck https://your-deploy.com --exit-on critical will fail any future deploy that includes a client_secret pattern.

Reference architecture (correct):

Browser  ── auth code ──>  Your backend  ── code + secret ──>  OAuth provider
Browser  <── session cookie ──  Your backend  <── access token ──  OAuth provider

The browser never sees the access token (it's stored server-side, behind a session cookie). The access token never sees the browser. The secret never sees the browser.

Did vibecheck flag this on your app?

If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.

Run another inspection