Verification runs with browser Web Crypto. Field values are not submitted or persisted.
PolicyWatcher
Loading verified public evidence
The page will appear when its current evidence state is available.
PolicyWatcher
The page will appear when its current evidence state is available.
Inspect the exact signed input and verify a deterministic public test vector in this browser. This readiness kit defines receiver interoperability; it does not provide webhook subscriptions or outbound delivery.
Verification runs with browser Web Crypto. Field values are not submitted or persisted.
The public vector checks signature compatibility. Its timestamp is evaluated at the recorded vector time, never by disabling production freshness.
No endpoint registration, outbound send, retry or delivery receipt is available here.
Change any field to test failure behavior, then restore the canonical vector. All computation remains on this device.
Run the published positive and negative cases in this browser. A passing run demonstrates fixture compatibility only; no endpoint or delivery is tested.
8 local cases are ready to run.
| Case | Purpose | Expected | Actual | State |
|---|---|---|---|---|
01canonical-validAccept the canonical vector | Confirms exact HMAC-SHA256 construction over the recorded timestamp and raw body. | valid | not_run | Not run |
02empty-secretReject an empty secret | Confirms fail-closed secret validation before digest construction. | invalid_secret | not_run | Not run |
03zero-timestampReject a zero timestamp | Confirms that the receiver accepts only positive integer Unix timestamps. | invalid_timestamp | not_run | Not run |
04stale-timestampReject a stale timestamp | Confirms enforcement immediately outside the candidate 300-second tolerance. | timestamp_outside_tolerance | not_run | Not run |
05unsupported-versionReject an unsupported signature version | Confirms strict parsing of the lowercase v1 signature prefix. | invalid_signature_header | not_run | Not run |
06uppercase-digestReject an uppercase digest | Confirms the canonical lowercase hexadecimal encoding contract. | invalid_signature_header | not_run | Not run |
07body-byte-mutationReject a raw-body byte mutation | Confirms that whitespace and exact raw-body bytes remain signature material. | signature_mismatch | not_run | Not run |
08digest-mutationReject a digest mutation | Confirms rejection of a well-formed but nonmatching signature value. | signature_mismatch | not_run | Not run |
This suite tests deterministic compatibility with the candidate receiver contract. It does not test endpoint identity, production secret custody, network delivery, retry behavior, replay storage, availability or implementation security outside these cases.
The browser workbench covers construction, calculation and comparison. Production receivers must also enforce freshness and replay controls.
Read the exact request bytes before any JSON parsing or reformatting.
Join the Unix timestamp, a period and the unchanged raw body.
Use the endpoint secret and encode the digest as lowercase hexadecimal.
Compare the receiver digest with the value after the v1 prefix.
Apply the timestamp window and reject event IDs already processed.
These examples verify the signature shape and digest. Add the production controls listed below before accepting a delivered event.
node:cryptoimport { createHmac, timingSafeEqual } from 'node:crypto';
const timestamp = request.headers.get('PolicyWatcher-Timestamp');
const signature = request.headers.get('PolicyWatcher-Signature');
const eventId = request.headers.get('PolicyWatcher-Event-Id');
const rawBody = Buffer.from(await request.arrayBuffer());
if (!/^\d+$/.test(timestamp ?? '') || !/^v1=[a-f0-9]{64}$/.test(signature ?? '')) {
throw new Error('Invalid webhook headers');
}
const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
if (age > 300) throw new Error('Stale webhook timestamp');
const expected = createHmac('sha256', process.env.POLICYWATCHER_WEBHOOK_SECRET)
.update(`${timestamp}.`, 'utf8')
.update(rawBody)
.digest('hex');
const supplied = signature.slice(3);
if (!timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(supplied, 'hex'))) {
throw new Error('Invalid webhook signature');
}
// Check eventId in a bounded replay store before processing.hmac · hashlibimport hashlib
import hmac
import os
import re
import time
timestamp = request.headers["PolicyWatcher-Timestamp"]
signature = request.headers["PolicyWatcher-Signature"]
event_id = request.headers["PolicyWatcher-Event-Id"]
raw_body = request.get_data(cache=False, as_text=False)
if not timestamp.isdigit() or re.fullmatch(r"v1=[a-f0-9]{64}", signature) is None:
raise ValueError("Invalid webhook headers")
if abs(int(time.time()) - int(timestamp)) > 300:
raise ValueError("Stale webhook timestamp")
message = timestamp.encode() + b"." + raw_body
expected = hmac.new(
os.environ["POLICYWATCHER_WEBHOOK_SECRET"].encode(),
message,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected, signature[3:]):
raise ValueError("Invalid webhook signature")
# Check event_id in a bounded replay store before processing.The public feed exposes already-published events with an opaque cursor. It does not imply delivery or receipt.