PHPackages                             philiprehberger/webhook-signature - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. philiprehberger/webhook-signature

ActiveLibrary[Payment Processing](/categories/payments)

philiprehberger/webhook-signature
=================================

Minimal, framework-agnostic HMAC-SHA256 webhook signature generation and verification with replay attack prevention

v1.1.4(1mo ago)116[1 PRs](https://github.com/philiprehberger/php-webhook-signature/pulls)MITPHPPHP ^8.2CI passing

Since Mar 6Pushed 1mo agoCompare

[ Source](https://github.com/philiprehberger/php-webhook-signature)[ Packagist](https://packagist.org/packages/philiprehberger/webhook-signature)[ Docs](https://github.com/philiprehberger/webhook-signature)[ RSS](/packages/philiprehberger-webhook-signature/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (3)Versions (7)Used By (0)

PHP Webhook Signature
=====================

[](#php-webhook-signature)

[![Tests](https://github.com/philiprehberger/webhook-signature/actions/workflows/tests.yml/badge.svg)](https://github.com/philiprehberger/webhook-signature/actions/workflows/tests.yml)[![Latest Version on Packagist](https://camo.githubusercontent.com/20eaf421e8950171bf033a38d8199a0484edfcfa8c7562d6fa00808b435f2db4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7068696c69707265686265726765722f7068702d776562686f6f6b2d7369676e61747572652e737667)](https://packagist.org/packages/philiprehberger/php-webhook-signature)[![License](https://camo.githubusercontent.com/9dd45d767e90272092752e951a362ce5402bc1149fa1e33d34b6dca44ab63f9b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f7068696c69707265686265726765722f776562686f6f6b2d7369676e6174757265)](LICENSE)

Minimal, framework-agnostic HMAC-SHA256 webhook signature generation and verification with replay attack prevention.

Requirements
------------

[](#requirements)

- PHP 8.2+

Installation
------------

[](#installation)

```
composer require philiprehberger/php-webhook-signature
```

Usage
-----

[](#usage)

### Sender Side — Signing an Outgoing Payload

[](#sender-side--signing-an-outgoing-payload)

```
use PhilipRehberger\WebhookSignature\WebhookSignature;

$payload = json_encode(['event' => 'invoice.paid', 'id' => 42]);
$secret  = 'your-shared-webhook-secret';

$signatureHeader = WebhookSignature::generate($payload, $secret);
// "t=1700000000,v1=a3f1...c9d2"

// Attach to your outgoing HTTP request
$response = $httpClient->post($endpointUrl, [
    'headers' => [
        'Content-Type'        => 'application/json',
        'X-Webhook-Signature' => $signatureHeader,
    ],
    'body' => $payload,
]);
```

### Receiver Side — Verifying an Incoming Webhook

[](#receiver-side--verifying-an-incoming-webhook)

```
use PhilipRehberger\WebhookSignature\WebhookSignature;

// Read the raw request body — do NOT decode it first
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$secret    = 'your-shared-webhook-secret';

if (! WebhookSignature::verify($payload, $signature, $secret)) {
    http_response_code(401);
    exit('Invalid signature');
}

// Signature is valid — process the payload
$data = json_decode($payload, true);
```

### Replay Attack Prevention

[](#replay-attack-prevention)

By default, signatures older than **300 seconds (5 minutes)** are rejected. Adjust the tolerance for your use case:

```
// Accept signatures up to 60 seconds old
$valid = WebhookSignature::verify($payload, $signature, $secret, tolerance: 60);

// Disable replay protection entirely (not recommended)
$valid = WebhookSignature::verify($payload, $signature, $secret, tolerance: PHP_INT_MAX);
```

### Exception-Based Flow with `verifyOrFail()`

[](#exception-based-flow-with-verifyorfail)

```
use PhilipRehberger\WebhookSignature\WebhookSignature;
use PhilipRehberger\WebhookSignature\Exceptions\InvalidSignatureException;
use PhilipRehberger\WebhookSignature\Exceptions\SignatureExpiredException;

try {
    WebhookSignature::verifyOrFail($payload, $signature, $secret);
} catch (SignatureExpiredException $e) {
    http_response_code(401);
    exit('Signature expired');
} catch (InvalidSignatureException $e) {
    http_response_code(401);
    exit('Invalid signature');
}
```

API
---

[](#api)

MethodDescription`WebhookSignature::generate(string $payload, string $secret, ?int $timestamp = null): string`Sign a payload; returns the formatted `t={ts},v1={hmac}` header value`WebhookSignature::verify(string $payload, string $signature, string $secret, int $tolerance = 300): bool`Verify a signature; returns `false` if malformed, expired, or invalid`WebhookSignature::verifyOrFail(string $payload, string $signature, string $secret, int $tolerance = 300): void`Verify a signature; throws `InvalidSignatureException` or `SignatureExpiredException` on failure`WebhookSignature::parseSignatureHeader(string $signature): ?array`Parse a signature header into `['timestamp' => int, 'v1' => string]`; returns `null` on malformed inputDevelopment
-----------

[](#development)

```
composer install
vendor/bin/phpunit
vendor/bin/pint --test
vendor/bin/phpstan analyse
```

License
-------

[](#license)

MIT

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance89

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

6

Last Release

56d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/cfd7d24cbbf32400fa13ce0bbe7a31edd2d66a6d4488eafdb3d64c5337bf0435?d=identicon)[philiprehberger](/maintainers/philiprehberger)

---

Top Contributors

[![philiprehberger](https://avatars.githubusercontent.com/u/8218077?v=4)](https://github.com/philiprehberger "philiprehberger (18 commits)")

---

Tags

securitysignaturestripewebhookhmacsha256

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/philiprehberger-webhook-signature/health.svg)

```
[![Health](https://phpackages.com/badges/philiprehberger-webhook-signature/health.svg)](https://phpackages.com/packages/philiprehberger-webhook-signature)
```

###  Alternatives

[payum/payum

One million downloads of Payum already! Payum offers everything you need to work with payments. Friendly for all PHP frameworks (Symfony, Laravel, Laminas, Yii, Silex). Check more visiting site.

1.9k6.6M21](/packages/payum-payum)[payum/payum-bundle

One million downloads of Payum already! Payum offers everything you need to work with payments. Check more visiting site.

59510.3M40](/packages/payum-payum-bundle)[cartalyst/stripe-laravel

Laravel 11 integration for the Cartalyst Stripe package.

3382.6M9](/packages/cartalyst-stripe-laravel)[omnipay/stripe

Stripe driver for the Omnipay payment processing library

1915.6M34](/packages/omnipay-stripe)[tightenco/nova-stripe

A tool to create a quick Stripe dashboard in your Laravel Nova admin panels

110308.9k](/packages/tightenco-nova-stripe)[flux-se/sylius-payum-stripe-plugin

Payum Stripe gateways plugin for Sylius.

61342.2k](/packages/flux-se-sylius-payum-stripe-plugin)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
