.env · security

Stripe Webhook Secret Generator

Generate a Stripe webhook secret (whsec_... format), GitHub webhook secret, Shopify HMAC secret, or generic webhook secret in your browser. Nothing is uploaded.

Be the first to rate
generated locally · crypto.getRandomValues · nothing sent anywhere
Stripe Webhook Secret
whsec_ prefix — paste into Stripe dashboard when registering endpoint
Secret value
.env line
STRIPE_WEBHOOK_SECRET=
GitHub Webhook Secret
Hex — matches GitHub's HMAC-SHA256 signature format
Secret value
.env line
GITHUB_WEBHOOK_SECRET=
Shopify Webhook Secret
Base64url — used to verify X-Shopify-Hmac-SHA256 header
Secret value
.env line
SHOPIFY_WEBHOOK_SECRET=
Generic Webhook Secret (hex)
64-char hex — works with any HMAC-SHA256 implementation
Secret value
.env line
WEBHOOK_SECRET=

What it does

  • Stripe STRIPE_WEBHOOK_SECRET in whsec_... format
  • GitHub webhook secret (hex, HMAC-SHA256 compatible)
  • Shopify webhook secret (base64url)
  • Generic HMAC-SHA256 webhook secret
  • All generated in-browser via crypto.getRandomValues

Privacy

Runs 100% in your browser. Your .env never touches our servers.

client-side only

When to use this tool

  • Creating a Stripe webhook endpoint and need a pre-generated secret
  • Setting up a GitHub Actions workflow triggered by repository webhooks
  • Generating a Shopify webhook HMAC secret for a custom app
  • Provisioning webhook secrets in a multi-environment deployment script

Common mistakes

  • Comparing signatures with === — always use timingSafeEqual or equivalent constant-time comparison
  • Not verifying webhook signatures at all — exposes your endpoint to spoofed events
  • Reusing the same secret across Stripe test and live modes
  • Hardcoding the secret in source code instead of loading from environment

What is a webhook secret?

When a service like Stripe sends a webhook to your endpoint, it signs the request body with a shared secret using HMAC-SHA256. Your server recomputes the signature with the same secret and compares — if they match, the request is genuine. Without this check, anyone on the internet could POST fake events to your endpoint.

Stripe webhook secret — whsec_ format

Stripe generates whsec_-prefixed secrets when you register a webhook endpoint. The prefix is cosmetic — Stripe strips it before using the value as an HMAC key. Verify in Node.js:

import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export async function POST(req: Request) {
  const body = await req.text();
  const sig = req.headers.get('stripe-signature')!;
  const event = stripe.webhooks.constructEvent(
    body, sig, process.env.STRIPE_WEBHOOK_SECRET!
  );
}

GitHub webhook secret

GitHub signs payloads with a hex HMAC-SHA256 in the X-Hub-Signature-256 header. Always use timingSafeEqual for comparison:

import { createHmac, timingSafeEqual } from 'crypto';

function verify(payload: string, sig: string, secret: string) {
  const expected = 'sha256=' + createHmac('sha256', secret).update(payload).digest('hex');
  return timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}

Frequently asked questions

Do I need to generate my own secret or will Stripe generate one automatically?

Stripe generates a whsec_... secret automatically when you register a webhook endpoint in the Stripe dashboard. You can also provide your own secret — useful when you want to use the same value across environments or store it before creating the endpoint. Both approaches are valid.

Why must I use timingSafeEqual instead of === to compare signatures?

Standard string comparison short-circuits on the first differing character, which leaks timing information. An attacker can measure response times to determine how many characters of a forged signature match the real one — eventually reconstructing it. timingSafeEqual (Node.js) and hmac.compare_digest (Python) always take the same time regardless of where strings differ.

Where should I store the webhook secret?

Store it in your .env as STRIPE_WEBHOOK_SECRET (or GITHUB_WEBHOOK_SECRET for GitHub, etc.). Never hardcode it in source code or commit it to git. In production, inject it via your deployment platform's environment variable settings — Vercel, Railway, Fly.io, or AWS Parameter Store.

What is the whsec_ prefix for?

The whsec_ prefix is cosmetic — it signals that the value is a webhook secret. Stripe strips it internally before using the value as an HMAC key. You cannot use a whsec_-prefixed value directly with standard HMAC libraries; strip the prefix first if constructing signatures manually.

Related tools

coming soon

Get notified when env syncing launches

We're building a tiny tool to keep .env files in sync across teammates and environments. Leave your email — no spam, just a single launch ping.