Back to Blog
Guide 5 min read2026-04-12

Stop Hardcoding API Keys — A Practical Guide

The single most common security finding across the SaaS apps we scan is API keys embedded in client-side code. It happens because it is the fastest path to a working integration: you grab the key from a dashboard, paste it into your component, and the feature works. But that key is now visible to every visitor who opens browser DevTools, and if it grants write access or has billing implications, you have a serious problem. Stripe secret keys, Supabase service role keys, OpenAI API keys, and SMTP credentials are the most frequent offenders we encounter.

The solution is to move all sensitive API calls to server-side code. In a Next.js app, this means API routes (app/api/) or server actions. Your frontend calls your own backend endpoint, and your backend calls the third-party API using the key stored in a server-only environment variable. This adds one network hop, but it completely eliminates client-side key exposure. For frameworks that support it, server components can also make these calls directly without an explicit API route, as long as the key is never imported into a client component. The rule of thumb is simple: if the file has "use client" at the top, no sensitive key should appear anywhere in its import chain.

Environment variable management matters too. Store keys in your hosting platform's environment settings (Vercel, Railway, or Fly.io all support this) rather than in .env files committed to your repository. If you must use .env files for local development, add .env* to your .gitignore file and provide a .env.example file with placeholder values so collaborators know which variables are needed. Audit your git history periodically, because a key that was committed in an early commit is still accessible even if the file was later deleted or added to .gitignore. Tools like git log --all -p -- .env can reveal whether this has happened.

For keys that must be in the browser (like the Supabase anon key or a Stripe publishable key), scope their permissions as narrowly as possible. The Supabase anon key is designed to be public, but only when RLS is properly configured. The Stripe publishable key can only create tokens, not charges. Understand the permission model of each key you use and verify that the public keys in your frontend cannot perform any destructive action. When in doubt, check the provider's documentation for guidance on which keys are safe for client-side use. A five-minute review of key permissions can prevent an incident that takes days to remediate.

Want to check your app for these issues?

Guardian scans your live app and finds these exact problems in under 5 minutes. No install, no CLI, no configuration.

Scan my app free