A web app needs Claude. Where should the API key live?
Why C is the answer
On your backend, which calls the API for the browser
Anything sent to the browser is public. Keep the key on your server, which is also where you add user auth and rate limits.
In detail
- Anything sent to a browser is public.
- Keep the key on your backend, which calls the API for the browser.
- That is also where you add user auth and rate limits.
- Rotate any key that has reached a browser.
Use case
An illustrative scenario, not a real incident.
A startup puts its key in the front end to ship quickly, and anyone can read it. A small backend route keeps the key server-side and adds sign-in and limits.
See it in different ways
flowchart LR A["Browser"] --> B["Your backend"] B --> C["Claude API with the secret key"]
sequenceDiagram participant P as Untrusted content participant C as Claude participant H as Hook in code participant T as Risky tool P->>C: Hidden instruction C->>H: Requests a risky action H--xT: Blocked by policy H-->>C: Denied, with a reason
sequenceDiagram participant P0 as Browser participant P1 as Your backend participant P2 as Claude API P0->>P1: Signed-in request P1->>P2: Request with the key P2-->>P1: Response P1-->>P0: Result only
Key point: Keys never reach the browser.
Why the other options are wrong
- A. In a public environment variable
- A public variable is exposed to the client.
- B. In local storage, encrypted in the browser after the user has signed in
- The browser has to be able to decrypt it, so the key is exposed there.
- D. In the browser JavaScript bundle
- Bundled JavaScript can be read by anyone.

