Content · Web Development · PHP

PHP Webhook Signature Verification and Replay Protection

Verify a webhook signature against the exact raw body and a bounded timestamp before processing the.

1 views Published Oct 17, 2026 Updated Oct 17, 2026 admin

Verify a webhook signature against the exact raw body and a bounded timestamp before processing the event.

The examples introduce the underlying control before showing a verification and an application-level safeguard.

What You Will Build


Verify a webhook signature against the exact raw body and a bounded timestamp before processing the event.

Prerequisites


Use PHP 8.4 or newer, HTTPS for all authentication operations, and an application session or database where required. Example configuration values are placeholders, never production secrets.

Example 1: Basic Operation


Compare an HMAC against the exact raw request bytes.

<?php
$secret = getenv('WEBHOOK_HMAC_KEY');
$rawBody = file_get_contents('php://input');
$received = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!is_string($secret) || $secret === '' || !is_string($received)) { http_response_code(401); exit; }
$expected = hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $received)) { http_response_code(401); exit; }

Example 2: A Different Use Case


Reject stale signed webhook timestamps.

<?php
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
if (!is_string($timestamp) || !ctype_digit($timestamp) || abs(time() - (int) $timestamp) > 300) {
    http_response_code(401); exit;
}
// Include the timestamp in the provider-defined signed payload, not as an unsigned check.

Practical Example: Checking the Result


Use an atomic uniqueness constraint to prevent concurrent replays.

<?php
$eventId = $_SERVER['HTTP_X_EVENT_ID'] ?? '';
if (!is_string($eventId) || !preg_match('/^[A-Za-z0-9_-]{8,128}$/D', $eventId)) { http_response_code(400); exit; }
// Atomically insert $eventId into a UNIQUE-indexed table before processing.
// A duplicate-key conflict indicates a replay and must not trigger side effects.

Important Behavior and Edge Cases


Never reserialize JSON before checking an HMAC, and persist event IDs or nonces atomically to block replay across workers.

Enforce controls on the server, test denial paths and do not assume that a snippet alone implements an entire production workflow.

Comparison with Related Functions


ApproachKey distinction
PHP Webhook Signature Verification and Replay ProtectionVerify a webhook signature against the exact raw body and a bounded timestamp before processing the event.
Related techniqueA signature establishes message authenticity; it does not provide idempotent business processing by itself.

Common Beginner Mistakes


MistakeCorrect approach
Confusing this operation with a neighboring cryptographic or security mechanismA signature establishes message authenticity; it does not provide idempotent business processing by itself.
Ignoring a security prerequisite or failure caseNever reserialize JSON before checking an HMAC, and persist event IDs or nonces atomically to block replay across workers.

Key Takeaways


  • Verify a webhook signature against the exact raw body and a bounded timestamp before processing the event.
  • Never reserialize JSON before checking an HMAC, and persist event IDs or nonces atomically to block replay across workers.
  • A signature establishes message authenticity; it does not provide idempotent business processing by itself.

Apply this behavior to a real application only after confirming the required extension, configuration and failure handling on the deployment runtime.

Share this resourceSend this page to someone who may find it useful.