Verifying webhook signature headers to prevent replay attacks

We’re catching Genesys Cloud outbound webhook events at a public endpoint, and the platform signs each payload with an X-GC-Signature header. The docs say to hash the raw body using HMAC-SHA256, so I’m running crypto.createHmac('sha256', secret).update(rawBody).digest('hex') in the middleware first. That part actually matches the incoming header fine. The real problem pops up when trying to block replay attacks. Genesys doesn’t send a standard timestamp header, so I’m pulling the event_time field from the JSON body instead. If I compare Date.now() - event_time against a 300ms window, the validation keeps rejecting valid events because the queue latency pushes things past the threshold.

Step one is verifying the HMAC matches, which works. Step two involves checking the event_time against a sliding window, but the latency keeps breaking it. I’ve got the middleware storing verified signatures in a Redis cache keyed by the event_id, yet the deduplication logic still lets duplicate POST requests slip through when the platform retries. The signature verification itself works, but the replay check feels completely off. Just checking the X-GC-Request-Id might not cut it either since that changes on retries anyway. Stuck on the exact comparison logic.

You’re right that Genesys doesn’t send a timestamp header for outbound webhooks. Since you can’t verify freshness server-side, you’ll need to handle replay protection locally. Store the signature in Redis with a short TTL, say 60 seconds, and reject any duplicate signatures within that window. It’s a bit of extra infra, but it’s the only reliable way to block replays here.