<?php
declare(strict_types=1);
namespace GNexus\GAuth\Tests\Unit\Webhook;
use GNexus\GAuth\Config\GAuthConfig;
use GNexus\GAuth\Contract\ClockInterface;
use GNexus\GAuth\Exception\WebhookVerificationException;
use GNexus\GAuth\Webhook\HmacWebhookVerifier;
use PHPUnit\Framework\TestCase;
final class HmacWebhookVerifierTest extends TestCase
{
public function testVerifiesValidSignature(): void
{
$clock = new class implements ClockInterface
{
public function now(): \DateTimeImmutable
{
return new \DateTimeImmutable('@1713900000');
}
};
$verifier = new HmacWebhookVerifier(
new GAuthConfig(
baseUrl: 'https://auth.example.test',
clientId: 'billing',
clientSecret: 'secret',
redirectUri: 'https://billing.example.test/callback',
webhookToleranceSeconds: 10,
),
$clock,
);
$body = '{"id":"evt_1","type":"webhook.test"}';
$timestamp = '1713900000';
$signature = hash_hmac('sha256', $timestamp . '.' . $body, 'whsec_test');
$verified = $verifier->verify($body, [
'X-GNexus-Event-Id' => 'evt_1',
'X-GNexus-Event-Type' => 'webhook.test',
'X-GNexus-Event-Timestamp' => $timestamp,
'X-GNexus-Signature' => 't=' . $timestamp . ',v1=' . $signature,
], 'whsec_test');
self::assertSame('evt_1', $verified->signatureId);
}
public function testRejectsTimestampOutsideTolerance(): void
{
$clock = new class implements ClockInterface
{
public function now(): \DateTimeImmutable
{
return new \DateTimeImmutable('@1713901000');
}
};
$verifier = new HmacWebhookVerifier(
new GAuthConfig(
baseUrl: 'https://auth.example.test',
clientId: 'billing',
clientSecret: 'secret',
redirectUri: 'https://billing.example.test/callback',
webhookToleranceSeconds: 10,
),
$clock,
);
$this->expectException(WebhookVerificationException::class);
$body = '{"id":"evt_1","type":"webhook.test"}';
$timestamp = '1713900000';
$signature = hash_hmac('sha256', $timestamp . '.' . $body, 'whsec_test');
$verifier->verify($body, [
'X-GNexus-Event-Id' => 'evt_1',
'X-GNexus-Event-Type' => 'webhook.test',
'X-GNexus-Event-Timestamp' => $timestamp,
'X-GNexus-Signature' => 't=' . $timestamp . ',v1=' . $signature,
], 'whsec_test');
}
}