Secure Stripe credentials for production

Stripe secret keys have direct access to your payment data. Keep the real key at the edge and give your code a token you can scope to specific endpoints and revoke.

Which Stripe keys to protect

Secret key (sk_live_...)

Direct API access - highest risk. Protect with KeyVault Edge.

Restricted keys

Scope-limited but still real credentials. Worth protecting.

Publishable key (pk_live_...)

Intentionally public - no need to protect.

Webhook signing secret

Used for signature verification - store in secret manager.

Setup

  1. 1.

    Create a Stripe token in the dashboard

    Go to Tokens → New Token, select Stripe as the provider. Paste your sk_live_... key. Add at least one allowed host (your server's domain).

  2. 2.

    Update your environment

    .env
    # BeforeSTRIPE_SECRET_KEY=sk_live_...real_key # After: the real key lives only in KeyVault EdgeSTRIPE_KVE_TOKEN=kvt_...your_token
  3. 3.

    Call Stripe through the proxy

    stripe.ts
    const res = await fetch("https://proxy.keyvaultedge.com/v1/balance", {  method: "GET",  headers: {    "X-KV-Token": process.env.STRIPE_KVE_TOKEN!,    "X-KV-Target": "https://api.stripe.com",    Origin: "https://app.yourdomain.com", // server-side: a host on the token's allowlist  },});console.log(res.status, await res.json());

    The proxy forwards the path to api.stripe.com and sets Stripe's Authorization header with your real key. The official Stripe Node SDK has no option for adding custom headers to every request, so use HTTP calls (or a thin wrapper) for proxied requests.

Production considerations

Stripe's idempotency keys and webhook endpoints are unaffected - these pass through the proxy unchanged. Stripe Connect and OAuth flows use the publishable key and do not require proxying.

For restricted keys (e.g., read-only for analytics), the same setup applies. You can also limit a token to specific endpoints (e.g. GET /v1/balance) when you create it.