{"_id":"@bookrail/webhook-signature","_rev":"5-c09c70b878e4d4f298a72f24b73a0392","name":"@bookrail/webhook-signature","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@bookrail/webhook-signature","version":"0.1.0","keywords":["webhook","webhooks","signature","hmac","verification","booking","bookrail"],"author":{"name":"MP Informatica Srl"},"license":"Apache-2.0","_id":"@bookrail/webhook-signature@0.1.0","maintainers":[{"name":"bookrail-dev","email":"hello@bookrail.dev"}],"homepage":"https://github.com/bookrail-dev/bookrail#readme","bugs":{"url":"https://github.com/bookrail-dev/bookrail/issues"},"dist":{"shasum":"3cb6e79e90b6775efa9cc1eea53e8cc58e196dd7","tarball":"https://registry.npmjs.org/@bookrail/webhook-signature/-/webhook-signature-0.1.0.tgz","fileCount":7,"integrity":"sha512-nljtsKEJ3rCFMzFY0dI6/43Lp+X08r1qzQzrLnZ9zwZziFzY7se+Vl8KSKj7QSM+g6aKSdUWuorIl3uQVb5CMA==","signatures":[{"sig":"MEQCIH5ywGqSxN14oFdLDweiOZDtj4CtlD2M/yxkYi1dzhuiAiBZzQ3qYqZEwhrP8yWw9hlzqL5YYi+z3U7N9cq8N9wI3Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43071},"main":"./dist/index.js","type":"module","_from":"file:bookrail-webhook-signature-0.1.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.10"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"lint":"eslint src test","test":"vitest run","build":"tsc -b","typecheck":"tsc -b --pretty && tsc -p tsconfig.test.json"},"_npmUser":{"name":"bookrail-dev","email":"hello@bookrail.dev"},"_resolved":"/private/var/folders/fx/qp06v39s47q53mrntyxhp3qh0000gn/T/9eddddce1dd3a25180e78d3112a10b7b/bookrail-webhook-signature-0.1.0.tgz","_integrity":"sha512-nljtsKEJ3rCFMzFY0dI6/43Lp+X08r1qzQzrLnZ9zwZziFzY7se+Vl8KSKj7QSM+g6aKSdUWuorIl3uQVb5CMA==","repository":{"url":"git+https://github.com/bookrail-dev/bookrail.git","type":"git","directory":"packages/webhook-signature"},"_npmVersion":"10.8.2","description":"Verify and sign Bookrail webhook payloads. Zero runtime dependencies: node:crypto only.","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","typescript":"^5.7.2","@types/node":"^20.17.10"},"_npmOperationalInternal":{"tmp":"tmp/webhook-signature_0.1.0_1789049739759_0.4360645997231565","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bookrail/webhook-signature","version":"0.2.0","keywords":["webhook","webhooks","signature","hmac","verification","booking","bookrail"],"author":{"name":"MP Informatica Srl"},"license":"Apache-2.0","_id":"@bookrail/webhook-signature@0.2.0","maintainers":[{"name":"bookrail-dev","email":"hello@bookrail.dev"}],"homepage":"https://github.com/bookrail-dev/bookrail#readme","bugs":{"url":"https://github.com/bookrail-dev/bookrail/issues"},"dist":{"shasum":"0b5596a5adbd8ed5e9a9ddbbd5a1dc863b42e921","tarball":"https://registry.npmjs.org/@bookrail/webhook-signature/-/webhook-signature-0.2.0.tgz","fileCount":7,"integrity":"sha512-+GuQfdeimlOovrA5lOqeFxcGgLX1dh1utWS3tyDP5x5EG7DaCDKeY7mtoBCOAH8U3ncSZtI0fLwQcMSyax6RCg==","signatures":[{"sig":"MEYCIQCHGCBLKuj3cSg8xxyh9/r6ZNF1uHefr1ofzIq/Y29rSAIhAM/bWdoXHAMe4GsYpfhsfzelGbqF2NbZRNv3VBoMavwd","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43071},"main":"./dist/index.js","type":"module","_from":"file:bookrail-webhook-signature-0.2.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.10"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"lint":"eslint src test","test":"vitest run","build":"tsc -b","typecheck":"tsc -b --pretty && tsc -p tsconfig.test.json"},"_npmUser":{"name":"bookrail-dev","email":"hello@bookrail.dev"},"_resolved":"/private/var/folders/fx/qp06v39s47q53mrntyxhp3qh0000gn/T/5e5638bbe87033fb0e0b9cbbc1a0c20d/bookrail-webhook-signature-0.2.0.tgz","_integrity":"sha512-+GuQfdeimlOovrA5lOqeFxcGgLX1dh1utWS3tyDP5x5EG7DaCDKeY7mtoBCOAH8U3ncSZtI0fLwQcMSyax6RCg==","repository":{"url":"git+https://github.com/bookrail-dev/bookrail.git","type":"git","directory":"packages/webhook-signature"},"_npmVersion":"10.8.2","description":"Verify and sign Bookrail webhook payloads. Zero runtime dependencies: node:crypto only.","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","typescript":"^5.7.2","@types/node":"^20.17.10"},"_npmOperationalInternal":{"tmp":"tmp/webhook-signature_0.2.0_1789116136996_0.3822590650942359","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bookrail/webhook-signature","version":"0.3.0","keywords":["webhook","webhooks","signature","hmac","verification","booking","bookrail"],"author":{"name":"MP Informatica Srl"},"license":"Apache-2.0","_id":"@bookrail/webhook-signature@0.3.0","maintainers":[{"name":"bookrail-dev","email":"hello@bookrail.dev"}],"homepage":"https://github.com/bookrail-dev/bookrail#readme","bugs":{"url":"https://github.com/bookrail-dev/bookrail/issues"},"dist":{"shasum":"e8039fc7d93ce9e50fb82a9dd0f723bf4e3d086c","tarball":"https://registry.npmjs.org/@bookrail/webhook-signature/-/webhook-signature-0.3.0.tgz","fileCount":7,"integrity":"sha512-jW6lWWQi5Q1j79C1RJbsMlqL9RZHo4aep/+mxVxiYZnVWud0Jk7LwM8LISquFQGVaNuJvVBpJ6rQa2o8BHCj0g==","signatures":[{"sig":"MEYCIQDwRi8JVyH6XPTq5CpBCfJlbSvy2RlzkQQqMWxh9HGNTgIhAIJ+opHwZ20/NwbFq+H2ZfB+2Mqzto25M0puaiK8nmcl","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43072},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20.10"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"319993e3ec164fa47e081781b16e87cbfe292640","scripts":{"lint":"eslint src test","test":"vitest run","build":"tsc -b","typecheck":"tsc -b --pretty && tsc -p tsconfig.test.json"},"_npmUser":{"name":"bookrail-dev","email":"hello@bookrail.dev"},"repository":{"url":"git+https://github.com/bookrail-dev/bookrail.git","type":"git","directory":"packages/webhook-signature"},"_npmVersion":"10.8.2","description":"Verify and sign Bookrail webhook payloads. Zero runtime dependencies: node:crypto only.","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","typescript":"^5.7.2","@types/node":"^20.17.10"},"_npmOperationalInternal":{"tmp":"tmp/webhook-signature_0.3.0_1789375731906_0.14961700585389104","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@bookrail/webhook-signature","version":"0.3.1","keywords":["webhook","webhooks","signature","hmac","verification","booking","bookrail"],"author":{"name":"MP Informatica Srl"},"license":"Apache-2.0","_id":"@bookrail/webhook-signature@0.3.1","maintainers":[{"name":"bookrail-dev","email":"hello@bookrail.dev"}],"homepage":"https://github.com/bookrail-dev/bookrail#readme","bugs":{"url":"https://github.com/bookrail-dev/bookrail/issues"},"dist":{"shasum":"52fd885074163e599403abc07ec8fd0dc8bca061","tarball":"https://registry.npmjs.org/@bookrail/webhook-signature/-/webhook-signature-0.3.1.tgz","fileCount":7,"integrity":"sha512-PE8Hivb4+LV06DdPj8R/X7fcR8Nmspu0MiA1QdyZ4rdCjJFQIUlYTZNaJJoaAtdEQGtQdNKCiTUCdvE9ZJlJCA==","signatures":[{"sig":"MEQCIDcpar43xShnXKMwHbfpS2Whp0NvDoAQpqJExKdh977gAiADrA1aV3Ub9YWIsUZb3VQDTb2tTntVNU2Z0dlYXZsj8A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43071},"main":"./dist/index.js","type":"module","_from":"file:bookrail-webhook-signature-0.3.1.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.10"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"lint":"eslint src test","test":"vitest run","build":"tsc -b","typecheck":"tsc -b --pretty && tsc -p tsconfig.test.json"},"_npmUser":{"name":"bookrail-dev","email":"hello@bookrail.dev"},"_resolved":"/private/var/folders/fx/qp06v39s47q53mrntyxhp3qh0000gn/T/943ceb6d430f1bdf94b7f30fc8121aa7/bookrail-webhook-signature-0.3.1.tgz","_integrity":"sha512-PE8Hivb4+LV06DdPj8R/X7fcR8Nmspu0MiA1QdyZ4rdCjJFQIUlYTZNaJJoaAtdEQGtQdNKCiTUCdvE9ZJlJCA==","repository":{"url":"git+https://github.com/bookrail-dev/bookrail.git","type":"git","directory":"packages/webhook-signature"},"_npmVersion":"10.8.2","description":"Verify and sign Bookrail webhook payloads. Zero runtime dependencies: node:crypto only.","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","typescript":"^5.7.2","@types/node":"^20.17.10"},"_npmOperationalInternal":{"tmp":"tmp/webhook-signature_0.3.1_1789376468582_0.6050466428183061","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"_id":"@bookrail/webhook-signature@0.4.0","bugs":{"url":"https://github.com/bookrail-dev/bookrail/issues"},"dist":{"shasum":"591239ff2b9583796902069c9e78b9d8e5292725","tarball":"https://registry.npmjs.org/@bookrail/webhook-signature/-/webhook-signature-0.4.0.tgz","fileCount":7,"integrity":"sha512-9t+cvkzJ0EcRCgyGFtS+VbJpnMDnh+KeSRloFFGbxjHgtety8bMmzz7r9Bn1wmEgIe4t7jLl27yuStGWbNatwQ==","signatures":[{"sig":"MEYCIQDSYdHiIUF2F6NiMVk05bl7w5lA9iEVloLJ9OabO2V7swIhALUIyNbtMZeYvFVCL1K5dEzbZ56Am2rSTskaBw4TlBcU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD0x0eqn+M8eLh4FIZZRCplEKf75kDcM3Ay4IdKPPUJcQIgLLxqWcRNcCftYrsXi0KwlX/gEcYhkUIUpAJdPdwrP2I="}],"unpackedSize":43071},"main":"./dist/index.js","name":"@bookrail/webhook-signature","type":"module","_from":"file:bookrail-webhook-signature-0.4.0.tgz","types":"./dist/index.d.ts","author":{"name":"MP Informatica Srl"},"engines":{"node":">=20.10"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"license":"Apache-2.0","scripts":{"lint":"eslint src test","test":"vitest run","build":"tsc -b","typecheck":"tsc -b --pretty && tsc -p tsconfig.test.json"},"version":"0.4.0","_npmUser":{"name":"bookrail-dev","email":"hello@bookrail.dev"},"homepage":"https://github.com/bookrail-dev/bookrail#readme","keywords":["webhook","webhooks","signature","hmac","verification","booking","bookrail"],"_resolved":"/private/var/folders/fx/qp06v39s47q53mrntyxhp3qh0000gn/T/db10b9591632c11ee1a2ecc92c41f75a/bookrail-webhook-signature-0.4.0.tgz","_integrity":"sha512-9t+cvkzJ0EcRCgyGFtS+VbJpnMDnh+KeSRloFFGbxjHgtety8bMmzz7r9Bn1wmEgIe4t7jLl27yuStGWbNatwQ==","repository":{"url":"git+https://github.com/bookrail-dev/bookrail.git","type":"git","directory":"packages/webhook-signature"},"_npmVersion":"10.8.2","description":"Verify and sign Bookrail webhook payloads. Zero runtime dependencies: node:crypto only.","directories":{},"maintainers":[{"name":"bookrail-dev","email":"hello@bookrail.dev"}],"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.8","typescript":"^5.7.2","@types/node":"^20.17.10"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webhook-signature_0.4.0_1790348298340_0.5799032467505865"}}},"time":{"created":"2026-09-10T14:15:39.295Z","modified":"2026-09-25T14:58:18.662Z","0.1.0":"2026-09-10T14:15:39.898Z","0.2.0":"2026-09-11T08:42:17.133Z","0.3.0":"2026-09-14T08:48:52.076Z","0.3.1":"2026-09-14T09:01:08.732Z","0.4.0":"2026-09-25T14:58:18.436Z"},"bugs":{"url":"https://github.com/bookrail-dev/bookrail/issues"},"author":{"name":"MP Informatica Srl"},"license":"Apache-2.0","homepage":"https://github.com/bookrail-dev/bookrail#readme","keywords":["webhook","webhooks","signature","hmac","verification","booking","bookrail"],"repository":{"url":"git+https://github.com/bookrail-dev/bookrail.git","type":"git","directory":"packages/webhook-signature"},"description":"Verify and sign Bookrail webhook payloads. Zero runtime dependencies: node:crypto only.","maintainers":[{"name":"bookrail-dev","email":"hello@bookrail.dev"}],"readme":"# `@bookrail/webhook-signature`\n\nVerify (and sign) Bookrail webhook payloads. **Zero runtime dependencies**: `node:crypto` and\nnothing else.\n\nThis is the one piece of Bookrail that runs on your machine rather than ours, so it is a\npackage of its own, small enough to install for the thirty two bytes it compares.\n\n```bash\nnpm install @bookrail/webhook-signature\n```\n\n```ts\nimport express from 'express';\nimport { verifySignature } from '@bookrail/webhook-signature';\n\napp.post('/hooks/bookrail', express.raw({ type: 'application/json' }), (request, response) => {\n  const ok = verifySignature(\n    request.body.toString('utf8'),          // the RAW bytes, exactly as they arrived\n    request.get('Bookrail-Signature'),\n    process.env.BOOKRAIL_WEBHOOK_SECRET!,\n  );\n  if (!ok) return response.sendStatus(400);\n\n  const event = JSON.parse(request.body.toString('utf8'));\n  // Deduplicate on event.id: delivery is at least once.\n  response.sendStatus(200);\n});\n```\n\n## The signature\n\n```\nBookrail-Signature: t=1789012345,v1=6f1c...\n```\n\n`v1` is `HMAC-SHA256(secret, \"<t>.<raw body>\")`, hex encoded.\n\nThe timestamp is **inside** the signed payload on purpose. Without it a signature is valid\nforever, and anyone who captured one delivery could replay it at any point in the future with\nno way for a receiver to tell. With it, a receiver that also checks the age of `t` has a\nbounded window. The default tolerance is 300 seconds, in both directions, because clock skew is\nsymmetric.\n\n## Three things that matter\n\n1. **Pass the raw bytes.** A body that was parsed and re-encoded will not verify: two JSON\n   encoders disagree about key order and whitespace. In Express that is `express.raw`, never\n   `express.json`.\n2. **It returns `false`, it never throws.** A receiver is by definition handling input from the\n   network, and a verifier that throws on a malformed header turns a forged request into a 500\n   instead of a 400.\n3. **The comparison is constant time**, and a header may carry several `v1=` values so a secret\n   can be rotated without a window in which deliveries fail. This function accepts if any of\n   them matches the secret you hold. Bookrail does not rotate secrets yet; the receiver you\n   deploy today keeps working on the day it starts.\n\n## API\n\n```ts\nverifySignature(body, header, secret, toleranceSeconds?, nowSeconds?): boolean\nparseSignatureHeader(header): { timestamp: number; signatures: string[] } | null\nsignPayload(body, secret, timestampSeconds): string    // the header value\ncomputeSignature(body, secret, timestampSeconds): string\nsignaturePayload(timestampSeconds, body): string       // \"<t>.<body>\"\n\nSIGNATURE_HEADER      // 'Bookrail-Signature'\nEVENT_ID_HEADER       // 'Bookrail-Event-Id'\nWEBHOOK_ID_HEADER     // 'Bookrail-Webhook-Id'\nDELIVERY_ID_HEADER    // 'Bookrail-Delivery-Id'\nDEFAULT_SIGNATURE_TOLERANCE_SECONDS   // 300\nSIGNATURE_SCHEME      // 'v1'\n```\n\n`@bookrail/node` wraps this in `webhooks.constructEvent(rawBody, header, secret)`, which\nverifies and parses in one call, and the `bookrail` CLI uses it in `webhooks listen`. One\nverifier in the whole project: a receiver that accepts a delivery nobody signed, or refuses one\nthat was signed, is a security bug either way, and two implementations would be one too many.\n\nESM only, Node 20.10 or newer.\n\n## Documentation\n\n[Webhooks](https://bookrail.dev/docs/guides/webhooks/): registering an endpoint, the retry\nladder, replays, deduplication, and the rule about which URLs are allowed to exist.\n\n## Status\n\nEarly access. This package is on npm as\n[`@bookrail/webhook-signature`](https://www.npmjs.com/package/@bookrail/webhook-signature),\nApache 2.0, with its source in\n[github.com/bookrail-dev/bookrail](https://github.com/bookrail-dev/bookrail) under\n`packages/webhook-signature`.\n\n## Licence\n\nApache-2.0.\n","readmeFilename":"README.md"}