Python / FastAPI

Secure Your Stripe API Key in Python

Python Stripe integrations often include the key in Django settings or Flask config dictionaries that get printed during exceptions. A leaked sk_live_ key allows attackers to drain your Stripe balance. KVE tokens fail outside your allowed hosts.

The Problem

This is what most Python 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.

Python
# payments.py — real Stripe key in environment
import os
import stripe

stripe.api_key = os.environ["STRIPE_SECRET_KEY"]  # sk_live_abc123...

def create_payment_intent(amount: int, currency: str) -> dict:
    intent = stripe.PaymentIntent.create(
        amount=amount,
        currency=currency,
        automatic_payment_methods={"enabled": True},
    )
    return {"client_secret": intent.client_secret}

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.

Python
# payments.py — KVE_TOKEN is host-bound; no Stripe key in process
import os
import httpx

KVE_TOKEN = os.environ["KVE_TOKEN"]

def create_payment_intent(amount: int, currency: str) -> dict:
    response = httpx.post(
        "https://proxy.keyvaultedge.com/v1/payment_intents",
        headers={
            "X-KV-Token": os.environ["KVE_TOKEN"],  # kvt_... token
            "X-KV-Target": "https://api.stripe.com",
            # Must match one of the token's allowed hosts
            "Origin": os.environ["APP_ORIGIN"],
        },
        # Stripe uses form-encoded bodies
        data={
            "amount": amount,
            "currency": currency,
            "automatic_payment_methods[enabled]": "true",
        },
        timeout=15.0,
    )
    response.raise_for_status()
    return {"client_secret": response.json()["client_secret"]}

Setup in 4 steps

1

Create a KVE token for your Python service

At keyvaultedge.com, create a token with your sk_live_ key, select Stripe as provider, and add your server's hostname as an allowed host. Create a second token for your sk_test_ key for development.

2

Update your environment

Replace STRIPE_SECRET_KEY with KVE_TOKEN in your .env or platform secret store.

Shell
# .env
KVE_TOKEN=kvt_...your_token
APP_ORIGIN=https://yourdomain.com  # one of the token's allowed hosts

pip install httpx
3

Replace stripe.PaymentIntent.create with httpx

Remove stripe.api_key assignment and the stripe SDK call. Use httpx.post to the KVE proxy with target set to https://api.stripe.com/v1/payment_intents.

4

Keep webhook validation unchanged

Your existing stripe.Webhook.construct_event call uses the STRIPE_WEBHOOK_SECRET, which is separate from the secret key. That stays exactly as-is. Only outbound API calls change.

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.