Every modern authentication platform needs a way to push events to downstream services in real time. Polling an API for status changes is wasteful, fragile, and introduces latency that compounds across distributed systems. Webhooks solve this by inverting the communication model: instead of your service asking "did anything happen?", the authentication provider tells you the moment something does. At H33, where a single API call executes fully homomorphic encryption, zero-knowledge proof verification, and post-quantum attestation in under 42 microseconds, reliable webhook delivery is not optional -- it is load-bearing infrastructure.
What Are Webhooks and Why They Matter
A webhook is an HTTP callback: a POST request that an upstream service sends to a URL you control whenever a specific event occurs. In the context of authentication, this means events like auth.success, auth.failure, key.rotated, user.enrolled, and threat.detected. Your endpoint receives a JSON payload describing the event, processes it, and returns a 2xx status code to acknowledge receipt.
Event-driven architectures built on webhooks enable real-time audit logging, immediate anomaly response, downstream service orchestration, and compliance reporting without ever polling. For security-critical systems, the latency difference between a 30-second polling interval and a sub-second webhook delivery can be the difference between catching an attack in progress and discovering it in a post-mortem.
The Security Threat Model
Webhooks expose an HTTP endpoint on your infrastructure that accepts inbound traffic from the internet. This creates a well-defined attack surface that must be hardened against four primary threats:
| Attack | Description | Mitigation |
|---|---|---|
| Spoofing | Attacker sends forged payloads to your endpoint | HMAC signature verification |
| Replay | Attacker captures and re-sends a legitimate payload | Timestamp validation window |
| Man-in-the-Middle | Attacker intercepts and modifies payloads in transit | TLS + signature verification |
| Timing | Attacker uses response-time differences to leak secret data | Constant-time comparison |
Every webhook implementation must address all four. Ignoring even one leaves your system vulnerable to exploitation. Let us walk through the defenses.
HMAC-SHA256 Signature Verification
The foundation of webhook security is cryptographic signature verification. When H33 sends a webhook, it computes an HMAC-SHA256 digest of the raw request body using a shared secret, and includes the result in the X-H33-Signature header. Your endpoint must recompute the same HMAC and compare. If they do not match, the payload was either forged or tampered with in transit.
Node.js Example
const crypto = require('crypto');
function verifyWebhook(req, secret) {
const signature = req.headers['x-h33-signature'];
const timestamp = req.headers['x-h33-timestamp'];
// Replay protection: reject payloads older than 5 minutes
const age = Math.abs(Date.now() / 1000 - parseInt(timestamp, 10));
if (age > 300) {
throw new Error('Webhook timestamp too old — possible replay');
}
// Compute HMAC over timestamp + body to bind them together
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${req.rawBody}`)
.digest('hex');
// Constant-time comparison to prevent timing attacks
const sig = Buffer.from(signature, 'hex');
const exp = Buffer.from(expected, 'hex');
if (!crypto.timingSafeEqual(sig, exp)) {
throw new Error('Invalid webhook signature');
}
return JSON.parse(req.rawBody);
}Python Example
import hmac, hashlib, time, json
def verify_webhook(headers: dict, body: bytes, secret: str) -> dict:
signature = headers['X-H33-Signature']
timestamp = headers['X-H33-Timestamp']
# Replay protection: 5-minute window
if abs(time.time() - int(timestamp)) > 300:
raise ValueError('Webhook timestamp expired')
# Compute HMAC over timestamp.body
expected = hmac.new(
secret.encode(),
f'{timestamp}.'.encode() + body,
hashlib.sha256
).hexdigest()
# Constant-time comparison
if not hmac.compare_digest(signature, expected):
raise ValueError('Invalid webhook signature')
return json.loads(body)Two critical details in both examples: the HMAC is computed over the concatenation of the timestamp and the raw body (separated by a period), which binds them together and prevents an attacker from swapping timestamps between payloads. And the comparison uses a constant-time function -- crypto.timingSafeEqual in Node, hmac.compare_digest in Python -- to eliminate timing side channels.
Replay Protection with Timestamp Validation
Even a perfectly signed payload can be dangerous if replayed. An attacker who captures a valid auth.success webhook could re-send it hours later, potentially granting unauthorized access if your system trusts it blindly. The defense is straightforward: include a Unix timestamp in the signed headers and reject any payload where the timestamp deviates from the current server time by more than five minutes. This window accounts for clock skew and network latency while keeping the replay surface minimal.
Idempotency Keys for Safe Retries
Networks are unreliable. H33 will retry webhook delivery with exponential backoff if your endpoint returns a non-2xx status code or times out. This means your handler must be idempotent -- processing the same event twice should produce the same result as processing it once. Every H33 webhook payload includes an idempotency_key field (a UUID v7 with embedded timestamp). Store this key in your database before processing, and skip any event whose key already exists.
Always check the idempotency key before performing side effects. If you process the event first and then check for duplicates, a crash between processing and recording will cause the event to be processed again on retry.
Post-Quantum Webhook Signatures
A question that arises frequently: are HMAC-SHA256 webhook signatures vulnerable to quantum computers? The short answer is no. HMAC is a symmetric construction -- Grover's algorithm provides at most a quadratic speedup, reducing the effective security of HMAC-SHA256 from 256 bits to 128 bits. That is still astronomically beyond any foreseeable computational capability. Symmetric cryptography, including HMAC, AES, and SHA-3, is inherently quantum-resistant.
The vulnerability lies in asymmetric signatures. RSA and ECDSA, which many webhook providers use for payload signing, are completely broken by Shor's algorithm on a sufficiently large quantum computer. This is where H33 diverges from the industry standard.
H33's Webhook Architecture: Dilithium-Signed Payloads
H33 offers two verification modes for webhooks. The first is standard HMAC-SHA256 with a shared secret, as shown above -- simple, fast, and already quantum-safe. The second is Dilithium (ML-DSA) digital signatures on every payload, providing asymmetric post-quantum verification without shared secrets.
With Dilithium-signed webhooks, H33 signs the payload using its private ML-DSA key, and you verify it using H33's published public key. This eliminates the need to distribute and rotate shared secrets entirely, and it provides non-repudiation: you can cryptographically prove that H33 (and only H33) generated a given payload. This matters for compliance regimes that require irrefutable audit trails.
Verifying a Dilithium-Signed H33 Webhook
const { ml_dsa65 } = require('@h33/pqc');
async function verifyH33Webhook(req) {
const payload = req.rawBody;
const signature = Buffer.from(req.headers['x-h33-dilithium-sig'], 'base64');
const timestamp = req.headers['x-h33-timestamp'];
// Replay protection
if (Math.abs(Date.now() / 1000 - parseInt(timestamp)) > 300) {
throw new Error('Timestamp expired');
}
// Fetch H33 public key (cache this -- it rotates quarterly)
const publicKey = await fetchH33PublicKey();
// Verify ML-DSA-65 signature over timestamp.body
const message = Buffer.from(`${timestamp}.${payload}`);
const valid = ml_dsa65.verify(publicKey, message, signature);
if (!valid) throw new Error('Invalid Dilithium signature');
return JSON.parse(payload);
}Dilithium (ML-DSA) is the NIST-standardized post-quantum digital signature scheme, based on lattice hardness assumptions. H33 uses ML-DSA-65 (Level 3 security) for webhook signatures, providing 128+ bits of post-quantum security with signature sizes of approximately 3,293 bytes -- compact enough for HTTP headers.
Implementation Checklist
Before deploying your webhook handler to production, verify every item on this list:
- Verify signatures on every request. Never skip verification, even in staging. Use constant-time comparison functions exclusively.
- Enforce a 5-minute timestamp window. Reject any payload with a timestamp that deviates from your server clock by more than 300 seconds. Ensure your servers run NTP.
- Persist idempotency keys before processing. Use a unique constraint in your database on the idempotency key column. Check before executing side effects.
- Return 2xx quickly, process asynchronously. Acknowledge receipt immediately, then queue the event for processing. H33 will time out and retry after 10 seconds.
- Use TLS exclusively. Your webhook endpoint must be HTTPS. H33 will not deliver to plaintext HTTP URLs.
- Log raw payloads for forensics. Store the raw request body, all headers, and the verification result. This is critical for incident response and compliance audits.
- Rotate secrets proactively. If using HMAC mode, rotate your webhook secret at least quarterly. H33's dashboard supports dual-secret verification during rotation windows to prevent downtime.
Event Types Reference
| Event | Trigger | Payload Fields |
|---|---|---|
auth.success | User passes FHE biometric + ZKP verification | user_id, confidence, latency_us, zkp_proof_id |
auth.failure | Verification fails threshold or ZKP check | user_id, reason, attempt_count |
key.rotated | API key or Dilithium keypair rotation | key_id, algorithm, effective_at |
threat.detected | AI agent flags anomalous pattern | threat_type, severity, source_ip, details |
user.enrolled | New biometric template encrypted and stored | user_id, template_id, fhe_scheme |
Every event payload includes a top-level event field, a timestamp (Unix seconds), an idempotency_key (UUID v7), and either an hmac or dilithium_signature depending on your configured verification mode.
Webhooks are deceptively simple in concept -- an HTTP POST with a JSON body -- but the security engineering required to handle them correctly in a production authentication system is substantial. Signature verification, replay protection, idempotent processing, and post-quantum readiness are not optional enhancements. They are the minimum bar. H33's dual-mode verification (HMAC-SHA256 for simplicity, Dilithium for post-quantum non-repudiation) gives you the flexibility to start simple and upgrade your security posture as quantum threats materialize, without changing your endpoint architecture.
Ready to Go Quantum-Secure?
Start protecting your users with post-quantum authentication today. 1,000 free auths, no credit card required.
Get Free API Key →