Signature Verification

Filoxenos signs all webhook events by including a signature in every X-Filoxenos-Signature header. This allows you to verify that the events were sent by Filoxenos and not by a third party.

Verification Steps

1

Extract the signature and timestamp

Retrieve X-Filoxenos-Signature and X-Filoxenos-Timestamp from the headers.

2

Prepare the signed payload

The signature is computed using the raw request body as a UTF-8 string.

3

Compute the HMAC-SHA256

Use your webhook secret to compute the HMAC signature of the payload.

Code Examples

Node.js

javascript
const crypto = require('crypto');

function verifyWebhook(payload, signature, timestamp, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  const received = signature.replace('sha256=', '');
  
  // Timing-safe comparison
  const valid = crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(received)
  );
  
  // Replay protection (5 minutes)
  const age = Math.abs(Date.now() / 1000 - parseInt(timestamp));
  if (age > 300) return false;
  
  return valid;
}

Python

python
import hmac, hashlib, time

def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    received = signature.replace('sha256=', '')
    
    if not hmac.compare_digest(expected, received):
        return False
    
    # Replay protection
    age = abs(time.time() - int(timestamp))
    return age <= 300

PHP

php
function verifyWebhook($payload, $signature, $timestamp, $secret) {
    $expected = hash_hmac('sha256', $payload, $secret);
    $received = str_replace('sha256=', '', $signature);
    
    if (!hash_equals($expected, $received)) return false;
    
    // Replay protection
    $age = abs(time() - intval($timestamp));
    return $age <= 300;
}
Never Skip Verification
Processing unverified webhooks exposes your application to spoofing and replay attacks. Always verify signatures in production environments.