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));
}