Secure Your Stripe API Key in Next.js
The Problem
This is what most Next.js codebases look like today. The STRIPE_SECRET_KEY key (sk_live_...) lives directly in the process environment. If your repo, your CI logs, or your deployment config leaks — so does your key.
// app/api/checkout/route.ts — real Stripe secret key in environment
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2025-05-28.basil",
});
export async function POST(req: Request) {
const { priceId } = await req.json();
const session = await stripe.checkout.sessions.create({
mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
success_url: "https://myapp.com/success",
cancel_url: "https://myapp.com/pricing",
});
return Response.json({ url: session.url });
}The Fix
Send the request to the KeyVault Edge proxy at https://proxy.keyvaultedge.com with the provider's usual path, your kvt_ token in X-KV-Token and the provider's base URL in X-KV-Target. The proxy refuses requests whose Origin isn't on the token's allowed hosts, then injects your real STRIPE_SECRET_KEY, so it never sits in your app's environment.
// app/api/checkout/route.ts — real key never in this process; KVE_TOKEN is host-bound
export async function POST(req: Request) {
const { priceId } = await req.json();
const response = await fetch("https://proxy.keyvaultedge.com/v1/checkout/sessions", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded", // Stripe uses form bodies
"X-KV-Token": process.env.KVE_TOKEN!, // kvt_... token, server-side only
"X-KV-Target": "https://api.stripe.com",
// Must match one of the token's allowed hosts
Origin: process.env.APP_ORIGIN!,
},
body: new URLSearchParams({
mode: "subscription",
"line_items[0][price]": priceId,
"line_items[0][quantity]": "1",
success_url: "https://myapp.com/success",
cancel_url: "https://myapp.com/pricing",
}),
});
const data = await response.json();
return Response.json({ url: data.url });
}Setup in 4 steps
Create a KVE token for your Stripe live key
At keyvaultedge.com, create a new token. Paste your sk_live_ key, set provider to Stripe, and bind it to your production domain (e.g. myapp.vercel.app). Never use the same token for test and live keys.
Update environment variables
Replace STRIPE_SECRET_KEY with KVE_TOKEN in .env.local and your Vercel/deployment environment settings.
# .env.local
KVE_TOKEN=kvt_...your_token
APP_ORIGIN=https://yourdomain.com # one of the token's allowed hosts
# Keep the publishable key — it's intentionally public
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...Replace the Stripe SDK checkout call with the KVE proxy
Remove the stripe package import from your route handler. Point the request at https://proxy.keyvaultedge.com with the provider's usual path (e.g. /v1/checkout/sessions), send your token in X-KV-Token, the provider's base URL (https://api.stripe.com) in X-KV-Target, and an Origin header matching one of the token's allowed hosts. The body is the provider's normal request body; the proxy sets the provider's auth header with your real key and forwards it. Stripe expects a form-encoded body.
Set up a breach-detection webhook
In the KeyVault Edge dashboard, add your Slack or PagerDuty webhook URL under Alerts. Any attempt to use your Stripe token from an unauthorized host fires an immediate notification.
What this protects, and what it doesn't
- Your real STRIPE_SECRET_KEY stays at the edge, so it can't leak from your repo, logs, bundle or server environment.
- The kvt_ token is still a credential. A copied token can be replayed by anyone who can send the right headers, including a fake Origin from a server. The protection is that each token has its own rate limits, monthly cost cap and endpoint scope, and you can revoke it in one click without rotating the provider key.
- The cost cap is estimated from the usage the provider reports, so a request already in flight can overshoot it slightly.
Plans and limits are on the pricing page.
Start protecting your keys
Your Stripe key is one leaked .env file away from being exploited. With KeyVault Edge the real key stays at the edge, and the token that replaces it is capped, scoped and revocable in one click.