> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tai42.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# webhook-verifier-github

> GitHub webhook-signature verifier plugin for the TAI ecosystem: a per-provider WebhookVerifier that checks each delivery's X-Hub-Signature-256 HMAC before the payload is dispatched.

<Info>`Webhook verifier` plugin · listing `tai42/webhook-verifier-github`</Info>

## Install

```bash theme={null}
tai plugins install tai42-webhook-verifier-github
```

## Permissions

| Capability | Declared |
| ---------- | -------- |
| Network    | no       |
| Subprocess | no       |
| Filesystem | no       |

## Provides

<h3 id="github">
  github
</h3>

`Webhook verifier` — Verify a GitHub webhook delivery's X-Hub-Signature-256 HMAC before dispatch.

Registers the `github` webhook verifier. It authenticates an inbound delivery's
`X-Hub-Signature-256` HMAC-SHA256, computed over the exact raw request body and keyed
by the webhook's shared secret. Bind it to a hook topic to close that topic's door
against unsigned deliveries.

## Bind it to a topic

A verifier is bound per hook topic. The binding names the environment variable that
holds the signing secret through `config.secret_env` — the verifier looks that
variable up at verify time, so the secret itself never lives in the manifest:

```bash theme={null}
curl -X PUT .../api/hooks/topics/{topic}/verifier \
  -d '{"verifier": "github", "config": {"secret_env": "GITHUB_WEBHOOK_SECRET"}}'
```

Set the same secret you configured on the GitHub webhook in that variable on every
process that receives deliveries:

```bash theme={null}
GITHUB_WEBHOOK_SECRET=...
```

The variable name is yours to choose — pick a distinct name per topic when one
deployment verifies several GitHub webhooks with different secrets.

### Replay window

GitHub sends no signed timestamp, so replay is defended by remembering each delivery's
`X-GitHub-Delivery` id in a seen-set. `config` takes an optional `replay_window_seconds`
(a positive int, default `86400` — one day) setting how long an id is remembered:

```json theme={null}
{"verifier": "github", "config": {"secret_env": "GITHUB_WEBHOOK_SECRET", "replay_window_seconds": 86400}}
```

A delivery whose id was already seen within that window is refused as a replay. A manual
redelivery of the same event carries the same id and is the correct idempotent no-op.

## Behaviour

* **Fails closed.** A missing `secret_env` key, a missing environment variable, an
  empty secret, a missing `X-GitHub-Delivery` header, or a non-positive / non-int
  `replay_window_seconds` raises loudly rather than degrading to an unauthenticated
  door. A malformed or mismatched signature is an ordinary verification failure.
* **Replay-deduped.** Each delivery's `X-GitHub-Delivery` id is remembered in a
  seen-set for `replay_window_seconds` (default one day); a replay within the window is
  refused and nothing re-dispatches.
* **POST only.** The signature covers the raw body, so a door binding this verifier
  rejects GET.
* The comparison is constant-time, and the `sha256=` digest must be exactly 64 hex
  characters.

## See also

* [Triggers and webhooks](/concepts/triggers-and-webhooks) — the verifier model and the built-in `shared_secret` verifier.
