Skip to content

React Tutorial Data and APIs

Why Secret Keys Must Not Be Exposed in Client-Side Code

Lesson 101 of 156 3 min read By Deepak Paswan Updated Oct 10, 2026

Full-project lesson · needs Node.js, npm and real project files, so it does not run in the in-page playground.

This is one of the most important lessons in the course, and the mistake it describes is very common. Any value your React code can read, every visitor can read. That includes values you thought you hid in an environment variable.

See the problem end to end

Imagine you call a paid service and put its secret key in a .env file, because tutorials say “use environment variables”:

.env
PLAIN
VITE_PAID_SERVICE_SECRET=sk_demo_not_a_real_key_12345

Your component uses it:

src/App.jsx
JSX
function App() {
  const key = import.meta.env.VITE_PAID_SERVICE_SECRET

  async function callService() {
    // This request would carry the secret to the paid service
    await fetch('https://api.paid-service.example/v1/generate', {
      headers: { Authorization: `Bearer ${key}` },
    })
  }

  return <button onClick={callService}>Calling the paid service</button>
}

export default App

The project builds without any warning. We built this project with Vite 8 and searched the output folder. The text sk_demo_not_a_real_key_12345 is in the built JavaScript file, in plain text. Anyone can:

  1. Open your site and press F12, go to Sources or Network.
  2. Open the JavaScript file, search for sk_, key or Bearer.
  3. Copy the key and use it on their own computer, at your expense, or read your data.

Minifying does not help. It only shortens variable names; strings stay readable. The VITE_ prefix does not help either: it means “send this to the browser”. That is its whole purpose.

Public keys and secret keys

Not every key is a secret. Services usually issue two kinds:

Public (publishable) keySecret key
Meant forBrowsers and mobile appsServers only
Can doLimited actions, such as showing a map or starting a checkoutAnything on your account: read all data, charge cards, send email, spend money
Safe in React?Yes, if it is restricted (to your domain, to specific APIs)Never
ExamplesA maps key restricted to your website, a payment provider’s “publishable” key, an analytics idA payment “secret” key, a database URL with a password, an admin token, an AI or email API key

Read the provider’s documentation to see which kind you have. If it says “keep this secret”, “server-side only” or the key grants billing power, it must stay on a server.

A key that is meant to be public should still be restricted in the provider’s dashboard: allowed websites, allowed APIs, spending limits and alerts.

The fix: a backend you control

Instead of calling the paid service from the browser, call your own backend. The backend holds the secret and calls the service:

code
PLAIN
Browser (React)  ──►  Your server  ──►  Paid service
  no secret         holds the secret     checks the secret
                    checks the user
                    limits the usage

Your React code becomes:

App.jsx
JSX
async function callService() {
  const response = await fetch('/api/generate', { method: 'POST', body: JSON.stringify({ prompt }) })
  // The server adds the secret key; the browser never sees it
}

The server (Node, PHP, Python, serverless functions or a framework route) reads the secret from a server-side environment variable, which is never included in the browser bundle, and:

  • authenticates the user (so strangers cannot use your endpoint),
  • validates the input,
  • rate-limits to control costs,
  • calls the third-party API, and
  • returns only what the browser needs.

Remember that your own endpoint is public too. If it lets anyone spend your money with no checks, you have only moved the problem.

What to do if a secret was exposed

Assume it is stolen the moment it ships, even briefly, even in a private repository or a deleted commit.

  1. Revoke or rotate the key in the provider’s dashboard right away.
  2. Put the new key on the server only.
  3. Check usage and logs for abuse.
  4. Remove it from Git history if needed (but rotating comes first; history rewriting does not make the old key safe again).
  5. Add a secret scanner to your repository and CI (many tools exist, and some hosts scan for you).

Other places secrets leak

  • Source maps published to production can expose original source code. Do not deploy them publicly if your code contains sensitive logic.
  • Hard-coded values in components, constants, test files or comments.
  • .env committed to a public repository. Keep real values in .env.local and ignore it.
  • URLs with keys (?api_key=...), which also land in browser history and server logs.
  • Browser storage and the Network tab. Anything you send from the browser can be seen there.

Key points

  • Everything in your bundle, including VITE_ variables, is readable by every visitor. The build in this lesson proves it.
  • Public, restricted keys can be used in React; secret keys belong on a server only.
  • Use a backend (or serverless function) as a proxy that authenticates, validates and rate-limits; rotate any key that ever shipped.