Skip to content
SaaS Security10 June 2026 · 7 min readUpdated 30 September 2026

Secrets Management and API Key Security for SaaS

API key security best practices for SaaS: how to store API keys securely, scope them to least privilege, rotate them, and respond when a secret leaks.

Secrets Management and API Key Security for SaaS

What you'll learn

  • What counts as a secret in a SaaS app?
  • How do you store API keys securely?
  • How do you scope and rotate keys?
Article contents

If you're not sure whether a key in your project is safe where it sits, run one check today: search your repository, your CI config and your built frontend bundle for the prefixes your providers use, such as sk_live_ and rk_live_ for Stripe. Any hit you didn't expect is a key to rotate, not just move.

API key security for a SaaS comes down to four habits: keep secrets out of the client bundle and out of Git, store them server-side in your host's secret store or a vault, give each key the least privilege it needs, and replace keys on a schedule and immediately after any exposure. This is a supporting guide under SaaS Security and Compliance; it zooms into where your secrets live and how you handle them.

The problem is large and growing. GitGuardian's State of Secrets Sprawl 2026 reports 28,649,024 new secrets detected in public GitHub commits during 2025, a 34% increase year over year, and found that 64% of the secrets it detected in 2022 were still active four years later, with only 36% rotated. Leaks are common, and they stay useful to attackers for a long time.

What counts as a secret in a SaaS app?

A secret is any value that grants access or trust to whoever holds it. In a typical SaaS that covers four groups, and every one of them can act on behalf of your whole application.

  • Payment provider secret keys. Stripe's documentation says that if an unauthorized party obtains your secret key, they can make unauthorized charges, access customer data, or interfere with your integration.
  • Database admin credentials. A Supabase secret key authorizes access through the service_role Postgres role, which has the bypassrls attribute, and Supabase says to never use it in the browser (Supabase RLS guide). Firebase Admin SDK credentials play the same role for Firestore.
  • Third-party API tokens. Email senders, AI APIs, mapping providers, analytics.
  • Signing and OAuth secrets. JWT signing keys, webhook signing secrets, session encryption keys, OAuth client secrets.

A useful test: if leaking the value lets someone impersonate your backend or read data they shouldn't, it belongs on the server only. The same GitGuardian report counts 1,275,105 AI-service secrets exposed in 2025, up 81% year over year, so a new AI API key deserves the same treatment as a payment key.

Which keys are public by design?

Some keys identify a project and are protected by other layers. Firebase's documentation says API keys for Firebase services only identify your project and app, that authorization is handled by IAM, Security Rules and App Check, and that keys restricted to Firebase services don't need to be treated as secrets (Firebase API keys). The same page warns that a Gemini Developer API key should never be included in your code or configuration files. Stripe publishable keys are safe in webpages and apps; secret keys must stay in your server environment (Stripe key best practices). Know which kind each key is before it goes anywhere near the frontend.

How do you store API keys securely?

Keep secrets out of source control and supply them at runtime: a gitignored .env locally, and your platform's secret store or a dedicated vault in production. Stripe's own guidance is to use a secrets vault where the platform has one and environment variables otherwise.

Local development. Put real values in a .env file that is gitignored before your first commit, and commit a .env.example with variable names and dummy values. Next.js's documentation notes that the default create-next-app template adds all .env files to .gitignore and that you almost never want to commit them (Next.js environment variables).

The client-bundle trap. In Next.js, variables are server-only by default, but any variable prefixed NEXT_PUBLIC_ is inlined into the JavaScript bundle at build time and sent to the browser. A secret that gets that prefix by mistake ships to every visitor. Pizzeria Bestek, my React and Supabase ordering build, is documented in its case study as separating client-visible VITE_* variables from server-only secrets, with every credential transferred to the client on launch.

Production. Use the platform's secret store so values are injected at build or runtime and never written into the repository. Stripe's guide lists AWS Secrets Manager, Google Cloud Secret Manager, Azure Key Vault and HashiCorp Vault as options, and says a vault adds an audit log of access, support for automatic rotation, and the ability to revoke access without redeploying.

Are environment variables enough?

For a small, early SaaS they are a reasonable start, but they have a known weakness. The OWASP Secrets Management Cheat Sheet points out that environment variables are generally accessible to all processes and may end up in logs or system dumps, and prefers fetching secrets from a dedicated store (OWASP). Stripe adds a practical rule: never show environment variables on error pages or in diagnostic modes. My recommendation: start with platform environment variables, mark sensitive ones as sensitive where your host supports it, and move to a vault when you need audit logs or automated rotation.

How do you scope and rotate keys?

Give every key the smallest permission set that does its job, separate keys by environment and service, and make replacement a routine you have practiced before you need it.

Stripe recommends restricted API keys with limited permissions instead of unrestricted secret keys, for example letting an invoicing system manage invoices and nothing else, or giving a third party read-only access to disputes (Stripe restricted keys). In practice:

  • Use sandbox or test keys in development and staging, and live keys only in production.
  • Give a background worker that sends email an email token, not your master credentials.
  • Keep privileged variants, such as service-role and admin credentials, on the server; use publishable or anon keys in the browser.

Why rotate on a schedule?

Stripe's guidance is that periodic rotation confirms you know where each key is used and that your team can replace one on short notice, and it recommends writing a contingency plan for exposure. The interval is your call; I'd start with whatever you can actually sustain and automate where the provider allows it, since OWASP warns that manual maintenance raises both leakage risk and the chance of human error.

Rotation is painless only if every key is read from one configuration entry. Then it's three steps: generate the new key at the provider, update the variable, redeploy. Keys scattered as string literals turn rotation into an archaeology project. Keep an inventory of every secret, where it's used and who issues it, and record when each was last rotated; that record also supports evidence for a SOC 2 audit, as in the SOC 2 Type 1 checklist.

What should you do after a key leaks?

Revoke and rotate the key immediately, even if you aren't sure anyone saw it, then remove it from the codebase and logs and record what happened. Deleting the commit alone isn't enough.

Stripe's guide says to rotate an exposed or compromised key immediately even if you aren't sure anyone saw it, and notes that Stripe may notify you or proactively deactivate a key it detects as exposed, without guaranteeing detection. OWASP's sequence is revoke, rotate, delete from exposed systems and logs, and log lifecycle details for the investigation. The GitGuardian numbers above show why: a value left active after exposure can stay useful for years.

To catch leaks before they land, use push protection. GitHub's documentation says it blocks detected secrets from pushes made from the command line, the GitHub UI, file uploads and the REST API, that protection for individual users is on by default for public repositories, and that repository-level protection needs an administrator to enable it (GitHub push protection). Contributors with write access can bypass it by giving a reason, so treat a bypass as an event worth reviewing. Stripe also suggests a pre-commit hook that rejects commits matching key patterns.

What does this look like on my own builds?

I only state what my case studies document. Callidus is a multi-tenant clinic SaaS on React and Firebase with Stripe Connect Standard and direct charges, where each clinic holds its own Stripe account; BookBed is a Flutter, Firebase and Stripe booking product whose subscription infrastructure is wired but not activated for paid traffic. Both are described in their case studies, Callidus and BookBed. If your data isolation is shaky, secret hygiene can't save you, which is why the foundation in multi-tenant SaaS architecture comes first, and why the Firestore rules for a clinic SaaS matter as much as the keys. If you also handle EU customer data, pair this with GDPR for B2B SaaS architecture.

Which single secret in your project would hurt most if it leaked tonight, and could you replace it in under an hour? If the answer is no, write that rotation runbook first.

Free resource

Free SaaS MVP Scope Template

A Notion document with the full feature checklist, MVP vs. nice-to-have table, pre-build questions, and cost signals — so you walk into any developer call knowing exactly what to ask for.

Get the template →
DL

Dusko Licanin

Full-Stack Developer · Banja Luka, Bosnia

Full-stack developer shipping SaaS MVPs, web apps, and mobile apps using AI-augmented workflows — without agency coordination overhead. Live portfolio: BookBed, Callidus, Pizzeria Bestek.

Frequently Asked Questions

How do I store API keys securely?

Keep API keys out of your source code and client bundle, and supply them at runtime from your platform's secret store or a dedicated vault. Locally, use a gitignored .env file with a committed .env.example that holds only variable names. In production, inject values through your host's environment-variable settings, marking sensitive ones as sensitive where supported. Move to a vault when you need access audit logs or automated rotation.

Is the Firebase web config a secret I need to hide?

No, Firebase's documentation says API keys for Firebase services only identify your project and app, and that keys restricted to Firebase services don't need to be treated as secrets. Protection comes from Security Rules, IAM and App Check. What must stay server-side are privileged credentials such as Admin SDK service accounts, and any non-Firebase keys, such as a Gemini Developer API key, which Firebase says must never be placed in your code or configuration files.

What do I do if I already committed a secret to Git?

Revoke and rotate the key at the provider immediately, even if you aren't sure anyone saw it, then remove it from the codebase and logs. Deleting the commit isn't enough, because the value may already have been copied or scraped, and GitGuardian's 2026 report found most secrets it detected in 2022 were still active four years later. Treat the old key as compromised and record when you replaced it.

Are environment variables enough, or do I need a secrets manager?

For a small, early-stage SaaS, environment variables on your hosting platform are a reasonable start. Their weakness, noted by the OWASP Secrets Management Cheat Sheet, is that they are generally accessible to all processes and can end up in logs or dumps. A dedicated secrets manager adds access audit logs, automated rotation and instant revocation, so plan to adopt one as your team or your risk grows.