Thank you for your interest in contributing! Tern is an algorithm-agnostic webhook verification framework. We welcome contributions for new platforms, algorithms, docs, and improvements.
Please read and follow our Code of Conduct.
- Node.js >= 22 or 20
- pnpm or npm
# Fork and clone
git clone https://github.com/Hookflo/tern.git
cd tern
# Install deps
npm install
# Build TypeScript
npm run build
# Run tests
npm testsrc/index.ts: Public API (WebhookVerificationService, helpers)src/platforms/algorithms.ts: Per-platform signature configurationsrc/verifiers/*: Algorithm and custom verifierssrc/normalization/*: Provider registries and templatessrc/utils.ts: Helpers for platform detection and signaturesdist/: Compiled output
- Create a feature branch:
git checkout -b feat/<short-name> - Commit with clear messages:
type(scope): short summary - Add/Update tests for your changes
- Run
npm run buildandnpm testbefore opening a PR
- TypeScript strict mode; no
anyunless unavoidable - Clear naming: descriptive variables and function names
- Early returns; avoid deep nesting
- Keep functions small and focused
- Match existing formatting; prefer multi-line for readability
There are two ways to support a new platform:
Most platforms can be added by defining a SignatureConfig in src/platforms/algorithms.ts.
Steps:
- Add an entry to
platformAlgorithmConfigswith keys:platform: the newWebhookPlatformkey (add tosrc/types.tsif missing)signatureConfig: includesalgorithm,headerName,headerFormat, optionaltimestampHeaderandtimestampFormat,payloadFormat, and optionalcustomConfigdescription: short description
- Ensure detection in
detectPlatformFromHeadersinsrc/utils.tsif applicable. - Exported APIs already work via
WebhookVerificationService.verifyWithPlatformConfig(request, '<platform>', secret).
Example snippet:
// src/platforms/algorithms.ts
platformAlgorithmConfigs.myplatform = {
platform: 'myplatform',
signatureConfig: {
algorithm: 'hmac-sha256',
headerName: 'x-myplatform-signature',
headerFormat: 'raw',
timestampHeader: 'x-myplatform-timestamp',
timestampFormat: 'unix',
payloadFormat: 'timestamped',
},
description: 'MyPlatform webhooks use HMAC-SHA256',
};If the platform requires special handling beyond SignatureConfig (e.g., token-based or asymmetric keys), implement or extend a custom verifier in src/verifiers/custom-algorithms.ts and wire it via algorithm: 'custom' with customConfig fields.
We support testing at multiple levels.
- Add tests under
src/**or test files referenced bynpm test(seepackage.json). - Prefer table-driven tests for multiple signature cases.
To test end-to-end verification, simulate a real webhook request:
- Build a raw HTTP request with headers and body matching your platform:
- Set the signature headers (e.g.,
stripe-signature,x-hub-signature-256,svix-*, etc.) - If timestamped payload is used, create payload as
{timestamp}.{body}or the configuredcustomConfig.payloadFormat.
- Set the signature headers (e.g.,
- Generate the expected signature using your
secretand configuredalgorithm:- For HMAC algorithms, compute HMAC over the payload string
- For token-based platforms, set headers
x-webhook-idandx-webhook-token
- Call the API:
import { WebhookVerificationService } from './src';
const result = await WebhookVerificationService.verifyWithPlatformConfig(
request, // a Request object with headers/body
'myplatform',
'my_secret',
300,
);- Assert
result.isValid === trueand validateresult.payloadandmetadata.
npm testruns the suite.- For selective testing, add a script like
npm run test:platform myplatformand wire it in tests.
See src/examples.ts and README examples for request construction and verification calls. Also check dist/ for compiled signatures of the public API to confirm outputs.
- Update
README.mdsections: Supported Platforms, examples if applicable. - Add notes to
USAGE.mdfor any new advanced configuration fields.
- Ensure all CI checks are green
- Include tests and documentation updates
- Keep PR focused and well-scoped
- Link related issues
- Fill out the PR template
Please follow our Security Policy to report vulnerabilities responsibly.
By contributing, you agree that your contributions will be licensed under the MIT License.