A browser is an untrusted environment. Users can inspect JavaScript bundles, network requests, source maps, browser storage, and extension activity. That makes one rule decisive: a secret API key cannot be securely hidden in frontend code. If the browser needs the key to make a request, a user can usually retrieve and reuse it.
The right goal is not to find a clever storage location. It is to design an architecture in which the browser receives only limited, short-lived credentials—or no provider credential at all.
What “browser API key storage” really means
API keys are commonly used to identify an application or authorize access to an API. Some providers issue public, domain-restricted keys for low-risk services such as map tiles, analytics, or client-side configuration. Others issue private keys that can create charges, read sensitive data, modify records, or access administrative functions.
Treat these categories differently:
- Public or publishable keys: May be used in the browser when the provider explicitly supports frontend use and offers strong restrictions.
- Secret API keys: Must remain on a trusted backend, serverless function, or managed integration.
- User access tokens: May be returned to a browser, but should be short-lived, narrowly scoped, and revocable.
- Configuration values: Endpoints, feature flags, and public identifiers are not secrets and can be shipped to the client.
For an AI product, this distinction is especially important. A frontend calling an LLM, vector database, payment provider, or enterprise data API directly can expose credentials, inflate usage bills, and bypass application-level authorization.
The safest default: keep secrets server-side
Use a backend-for-frontend (BFF), API route, serverless function, or application server as the boundary between the browser and third-party services. The browser authenticates to your application; your server authenticates to the provider.
A typical flow is:
1. The user signs in to your application.
2. The browser sends an authenticated request to your backend.
3. The backend checks authorization, validates input, and applies rate limits.
4. The backend adds the provider API key from a secret manager.
5. The backend returns only the minimum required response.
Store the provider key in deployment-time secrets or a dedicated secret manager—not in a JavaScript bundle, HTML file, Git repository, Docker image layer, or frontend .env variable. Many frontend build tools expose variables with names such as PUBLIC_, NEXT_PUBLIC_, or VITE_ to every visitor; those are configuration channels, not secure storage.
This pattern also gives Indian startups practical control over cost, data residency decisions, audit logs, abuse detection, and provider failover. Teams building production AI systems should pair it with full-stack AI engineering best practices, particularly around observability and service boundaries.
When a browser-safe key is acceptable
Some services intentionally support browser keys. Examples can include map SDKs, CAPTCHA public site keys, and publishable payment identifiers. Use a client-side key only when all of the following are true:
- The provider documents it as safe for frontend use.
- The key is restricted by allowed origins, APIs, products, quotas, or referrers.
- It cannot read private records or perform privileged operations.
- Billing and abuse limits are configured.
- You can revoke and replace it quickly.
Origin restrictions are useful but not absolute protection. They reduce casual misuse, yet attackers can still reproduce requests from an allowed website, abuse a compromised session, or exploit permissive server-side validation. Never treat CORS as authentication: CORS controls browser behavior, not whether a remote service receives a request.
Browser storage choices: what they can and cannot protect
localStorage
localStorage is easy to use but unsuitable for long-lived secrets. Any JavaScript running in the page can read it, so a cross-site scripting (XSS) vulnerability or compromised dependency can exfiltrate stored tokens. It also persists across sessions and is accessible to every tab under the origin.
sessionStorage
sessionStorage limits persistence to a tab session, but it remains readable by JavaScript. It reduces exposure duration; it does not defend against XSS. Use it only for low-risk, short-lived client state when the token model and threat assessment justify it.
IndexedDB
IndexedDB is useful for larger client-side datasets and offline applications, but it is not a secret vault. The same-origin page can generally access its contents. Do not choose IndexedDB merely because it is less visible than localStorage.
Cookies
For session authentication, an HttpOnly, Secure, SameSite cookie is generally safer than storing a long-lived token in web storage. HttpOnly prevents page JavaScript from reading the cookie, while Secure restricts transmission to HTTPS. Configure SameSite according to your cross-site requirements and add CSRF protection where needed.
Cookies are not automatically secure. XSS can still perform actions through a victim’s browser, and incorrect domain, path, or SameSite settings can create weaknesses. Keep sessions short, rotate them after sensitive events, and revoke them server-side.
Prefer scoped, short-lived credentials
When direct browser access is unavoidable, issue an ephemeral credential from your backend. Limit it by:
- Time: Expire it in minutes, not months.
- Scope: Permit only specific operations or resources.
- Audience: Bind it to the intended service or application.
- Quota: Restrict requests, spend, tokens, or bandwidth.
- Context: Associate it with a user, session, device, or transaction where possible.
OAuth 2.0 with Authorization Code and PKCE is a stronger fit for delegated user access than embedding a static provider key. JWTs can carry claims, but signing a JWT does not make a browser-held token secret; design expiry, revocation, audience validation, and key rotation carefully.
Common mistakes to remove from your codebase
- Putting secrets in frontend environment variables and assuming the build system hides them.
- Committing
.envfiles, source maps, screenshots, logs, or CI artifacts containing credentials. - Relying on minification or obfuscation. Anyone can inspect runtime values and network traffic.
- Sending provider keys in query strings, where they may appear in browser history, proxies, and logs.
- Allowing the browser to choose an arbitrary upstream URL, creating a proxy or SSRF risk.
- Returning entire provider responses when the client needs only a few fields.
- Skipping server-side authorization because the UI hides a button.
- Reusing one unrestricted key across development, staging, and production.
Use automated secret scanning in Git hooks and CI, review dependency changes, and document credential ownership. Teams maintaining public repositories can also learn from best practices for documenting open-source AI codebases.
A practical implementation checklist
Before shipping a browser-integrated API:
- Classify every credential as public, user-scoped, or secret.
- Move secret calls behind a backend or serverless endpoint.
- Use a managed secret store and inject credentials at runtime.
- Enforce authentication, authorization, input validation, quotas, and rate limits server-side.
- Set provider restrictions, separate environments, and configure billing alerts.
- Use HTTPS everywhere and secure, HttpOnly cookies for suitable sessions.
- Issue short-lived, narrowly scoped tokens when direct access is required.
- Redact secrets from logs and error messages.
- Rotate credentials periodically and immediately after suspected exposure.
- Test the production bundle, source maps, network panel, and repository history for leaks.
For browser-heavy applications, include security checks in automated testing rather than relying on manual review. Browser test automation can verify that sensitive values do not appear in page scripts, responses, URLs, or client storage; see how to automate browser tests for a broader testing workflow.
What to do after a key is exposed
Assume a published key is compromised. Revoke or rotate it first, then inspect provider logs for unusual IPs, origins, endpoints, spending, and data access. Remove the key from active code, but remember that deleting a Git commit does not remove it from forks, caches, or repository history. Rewrite history where appropriate and invalidate related sessions or tokens.
Finally, identify the architectural cause. If the browser required a secret, replace the direct integration with a backend boundary or ephemeral credential flow. Security improves when exposure is prevented by design, not when leaked values are merely hidden more effectively.
FAQ
Can I hide an API key with JavaScript obfuscation?
No. Obfuscation slows casual inspection but does not protect a value delivered to the browser. Use a backend proxy or a provider-approved publishable key with restrictions.
Is localStorage safe for API tokens?
It is readable by JavaScript and therefore vulnerable to token theft through XSS or malicious dependencies. Prefer secure, HttpOnly cookies for suitable sessions, or short-lived in-memory tokens with a carefully designed refresh flow.
Are API keys in .env files secure?
Only when the file remains on a trusted server or deployment system. Frontend build tools often embed selected variables into publicly downloadable assets.
Should I use OAuth instead of an API key?
For delegated user access, OAuth 2.0 with PKCE is usually more appropriate. It still requires careful scope, expiry, redirect URI, storage, and revocation design.
Where should Indian startups begin?
Inventory credentials, move secrets behind server-side endpoints, enable provider restrictions and spend alerts, and establish rotation and incident-response procedures before scaling usage.