Security
Security best practices for webhook verification, secret handling, and replay protection.
Security
Verify every webhook request
Use provider signature verification for all production endpoints.
Better Webhook verifies signatures automatically when secrets are configured.
Secret resolution order:
- Adapter options
- Provider options
- Provider environment variables
Examples:
GITHUB_WEBHOOK_SECRETSTRIPE_WEBHOOK_SECRETRAGIE_WEBHOOK_SECRETRECALL_WEBHOOK_SECRETRESEND_WEBHOOK_SECRET
Preserve raw request bodies
Signature verification depends on exact raw bytes. If middleware mutates the body before verification, checks may fail.
- Express: use
express.raw({ type: "application/json" })for webhook routes. - NestJS: ensure raw request body handling is configured before adapter invocation.
- GCP Cloud Functions: adapter reads raw body from platform request data.
See Adapters for framework details.
Protect secrets and rotate when needed
- Store secrets in environment variables or your secret manager.
- Never commit secrets to git.
- Rotate secrets if leaked or if providers indicate suspicious activity.
- Keep separate secrets for dev/staging/production.
Enable replay protection for idempotency-sensitive handlers
Use replay protection when duplicate delivery can cause side effects:
import { createInMemoryReplayStore } from "@better-webhook/core";
import { github } from "@better-webhook/github";
const replayStore = createInMemoryReplayStore();
const webhook = github().withReplayProtection({ store: replayStore });Choose a durable store for production deployments that run across multiple instances.
Handle verification failures explicitly
Use .onVerificationFailed() and .onError() to log and monitor security-relevant failures.
webhook
.onVerificationFailed((reason) => {
console.warn("Verification failed:", reason);
})
.onError((error, context) => {
console.error(`Webhook error in ${context.eventType}`, error);
});Disabling signature verification in production is unsafe and not recommended.