← Blog

Secure Storage for Claude API Keys in Production

2026-09-30 · 5 min read · SubToAPI Team

Storing a Claude API key securely in production means keeping it out of source control, out of client-side code, and out of plaintext config files — and instead loading it at runtime from a dedicated secrets manager or environment variable injection system with tightly scoped access. The short version: never hardcode it, never ship it to a browser, rotate it on a schedule, and give each service or team its own key so you can revoke one without breaking everything else.

That answers the "where do I put it" question. The harder part is doing this consistently across environments, teams, and CI pipelines without slowing anyone down. Below is a practical breakdown of what actually works.

Where NOT to put your key

Before the "right" way, a quick list of the mistakes that cause leaked keys in the wild:

If any of these sound familiar, treat the key as compromised and rotate it.

The baseline: environment variables

For most teams, environment variables injected at runtime (not build time) are the minimum acceptable standard:

export CLAUDE_API_KEY=sk-ant-xxxxxxxxxxxxxxxx
const apiKey = process.env.CLAUDE_API_KEY;
if (!apiKey) {
  throw new Error("CLAUDE_API_KEY is not set");
}

This works fine for a single server or container, but it has limits: env vars are visible to any process running in the same container, they're easy to accidentally log, and they don't give you rotation, scoping, or an audit trail on their own.

The production standard: a secrets manager

For anything running in production with multiple services or team members, use a dedicated secrets manager — AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, or your platform's built-in equivalent (Vercel, Fly.io, Render, and similar all have first-class secret storage). The pattern is the same regardless of provider:

  1. Store the key encrypted at rest in the secrets manager.
  2. Grant your application's runtime role read access via IAM/policy, not a static credential.
  3. Fetch the secret at process startup and hold it in memory — never write it to disk.
  4. Set up automatic rotation if your provider supports it, or a manual rotation runbook if it doesn't.
// Example: fetching from AWS Secrets Manager at startup
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";

const client = new SecretsManagerClient({ region: "eu-west-1" });
const response = await client.send(
  new GetSecretValueCommand({ SecretId: "prod/claude-api-key" })
);
const apiKey = response.SecretString;

This removes the key from your deployment config entirely — your CI/CD pipeline never sees the plaintext value, and access is governed by the same IAM policies as the rest of your infrastructure.

Scope keys per service, not one key for everything

A single shared API key used by every microservice, cron job, and internal tool is a single point of failure. If one service gets compromised, you have to rotate the key everywhere simultaneously, which usually means downtime.

Instead:

This is one of the reasons teams put Claude behind an internal gateway rather than distributing the raw Anthropic key directly. SubToAPI, for example, issues separate sub_live_... application keys per app or environment from a single underlying Claude subscription, so you can revoke a staging key without touching production, and see usage broken down per key in the dashboard. You generate keys after signup and use them exactly like a normal bearer token:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Summarize this ticket."}]
  }'

Full request/response details are in the API docs, and the quickstart covers getting a key from a fresh signup to a working call in a few minutes.

Rotation without downtime

Rotating a key shouldn't require a deploy. The standard pattern:

  1. Generate a new key alongside the old one (most providers support multiple active keys).
  2. Update your secrets manager with the new value.
  3. Restart or let your services pick up the new value on their next secret refresh cycle.
  4. Confirm traffic is flowing on the new key (check usage metadata if your provider exposes it).
  5. Revoke the old key.

Do this on a fixed schedule — quarterly is a reasonable default for most teams — and immediately whenever someone with key access leaves, or a key is suspected to have leaked (e.g., found in a log, a public repo, or a shared screen).

Don't forget local development

Local .env files are fine for development as long as:

Quick checklist

Questions

Is it safe to put a Claude API key in a .env file? Yes for local development, as long as .env is gitignored from the first commit. For production, prefer a secrets manager over a .env file on a server, since secrets managers give you access control, rotation, and an audit trail.

Can I use the same API key across all my environments? You can, but you shouldn't. Separate keys per environment (dev/staging/prod) and per service let you revoke or rate-limit one without affecting the others, and make it much easier to trace where a spike in usage or a leak came from.

How often should I rotate a production API key? A fixed schedule (quarterly is common) plus immediate rotation whenever a key may have been exposed — found in a log, committed to git, or accessible to someone who's left the team. Automate it where your provider supports programmatic key creation and revocation.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →