npm package: @fygaro/webhook
Description: Webhook signature verification for Fygaro
Latest version: 1.2.0

# @fygaro/webhook

> **Verify Fygaro webhooks in Node / TypeScript — zero runtime deps**

Works on Node ≥ 16, edge runtimes and test
environments. No optional peer dependencies.

---

## Installation

```bash
npm i @fygaro/webhook
```

---

## Quick start

```ts
import { FygaroWebhookValidator } from "@fygaro/webhook";

const validator = new FygaroWebhookValidator({
  secrets: [
    process.env.FYGARO_SECRET!,          // current secret
    // process.env.FYGARO_OLD_SECRET!,   // add during rotation
  ],
  // maxAge: 300,                        // default ⇢ 5 minutes
});

const sigHeader = req.headers["fygaro-signature"] as string;
const rawBody   = req.rawBody as Buffer;   // **unmodified** request body

if (!validator.verifySignature(sigHeader, rawBody)) {
  res.status(400).send("Invalid signature");
  return;
}

// ...process JSON, return 200...
```

### Opt-in: detailed error handling

```ts
import {
    FygaroWebhookValidator,
    SignatureVerificationError,
} from "@fygaro/webhook";

const validator = new FygaroWebhookValidator({
    secrets: [process.env.FYGARO_SECRET!],
    throwOnError: true,
});

try {
    validator.verifySignature(
        req.headers["fygaro-signature"] as string,
        req.rawBody as Buffer,
    );

} catch (err) {
    if (err instanceof SignatureVerificationError) {
        console.warn("Webhook rejected:", err.message);
        res.status(400).send(err.message);
        return;
    }
}
```

---

## API

### `new FygaroWebhookValidator(options)`

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `secrets` | `Array<string \| Uint8Array>` | **required** | One or more active signing secrets. Provide both new **and** previous secrets during a rotation window. Each value may be a UTF‑8 string or a `Buffer`/`Uint8Array`. |
| `maxAge` | `number` | `300` | Acceptable clock skew (seconds) between the header timestamp and server time. Lower values reduce replay‑attack risk. |
| `unsafeSkipTsValidation` | `boolean` | `false` | **Test‑only.** When `true` the timestamp‑freshness check is skipped and a console warning is printed on instantiation. Never enable in production. |
| `throwOnError` | `boolean` | `false` | When `true`, failures raise subclasses of `SignatureVerificationError`; when `false` (default) the method simply returns `false`. |

---

### Legacy positional constructor *(deprecated)*

The old positional overloads continue to work but will be removed in **v2.0.0**:

```ts
// v1.x (deprecated)
new FygaroWebhookValidator([secret], 300, /* skip? */ false);
```

Creating an instance with the positional form prints a one‑time deprecation
warning. Please migrate to the options object shown above.

---

### `validator.verifySignature(signatureHeader, body) → boolean`

| Param | Type | Description |
|-------|------|-------------|
| `signatureHeader` | `string` | Exact value of the **Fygaro‑Signature** header. |
| `body` | `Uint8Array \| Buffer \| string` | Raw request body *exactly as received*. Do **not** JSON‑parse or re‑serialize. |

Returns `true` when:

1. The HMAC matches **any** provided secret, **and**
2. The header timestamp is within `maxAge` *(unless skipped).*

### Exception classes

* `SignatureVerificationError` (base)
* `MissingHeaderError`
* `TimestampInvalidError`
* `TimestampExpiredError`
* `SignatureMismatchError`


---

## Deterministic unit tests

Skip the freshness gate to keep fixtures tidy:

```ts
const validator = new FygaroWebhookValidator({
  secrets: ["test-secret"],
  unsafeSkipTsValidation: true,
});

expect(validator.verifySignature(header, body)).toBe(true);
```

The first instance created with the flag prints:

```
[fygaro-webhook] Timestamp validation DISABLED – for test use only!
```

---

## Changelog

See [`CHANGELOG.md`](https://unpkg.com/@fygaro/webhook@latest/CHANGELOG.md) for full release notes.

---

## License

MIT © Fygaro — support · support@fygaro.com