Verifying requests
How every call from Storeware to your app is signed, and how to check it.
Every request Storeware makes to your app (webhooks, tools, knowledge and storefront blocks) is signed the same way. Verify v2, and never accept v1 alone: it signs no kind, so a webhook captured on its way to you could be replayed at your tool endpoint.
Not writing JavaScript? Verifying in other languages has the same checks in Python, PHP, Go and Ruby, and test vectors to run them against.
Verifying one
Every delivery is signed with the secret shown once when you created the endpoint. Compare it in constant time and reject anything you cannot verify: an unverified webhook is an instruction from anybody who guessed your URL.
import { verifyWebhook } from '@storeware/plugin-sdk/webhooks';
// The SDK does this for you, and is the recommended route. It throws on
// anything it cannot verify, so a forgotten check cannot pass silently.
const event = verifyWebhook({
secret: SECRET,
rawBody,
signatureHeader: req.get('storeware-signature'),
});One header, storeware-signature, carrying the time and two signatures:
storeware-signature: t=1754400131,v1=9f2ae1c4...,v2=41c07b2e...
storeware-kind: webhookv2 is HMAC-SHA256 over `${t}.${kind}.${rawBody}` with your secret,
hex encoded, where kind is webhook for a webhook. The same secret signs
every call Storeware makes to an app (webhooks, tool calls, knowledge requests,
storefront blocks), and the kind inside v2 is what stops a request captured on
its way to one of your endpoints from verifying at another. v1 is the older
`${t}.${rawBody}` signature, still sent so integrations written against it
keep working; it says nothing about the kind, so check v2 in anything new.
If you would rather not take the dependency, compute v2 yourself and compare
in constant time, and reject anything where t is more than five minutes old:
a signature stays valid forever without that check, so a captured request can
be replayed indefinitely.
Verify against the raw body, before any JSON parsing. Re-serialising an object does not reproduce the bytes that were signed, and a handler that parses first will fail every signature and eventually be "fixed" by removing the check.