# `Tink.WebhookVerifier`
[🔗](https://github.com/iamkanishka/tink.ex/blob/v0.1.1/lib/tink/webhook_verifier.ex#L1)

Webhook signature verification for Tink webhooks.

Tink signs webhook payloads using HMAC-SHA256 to ensure authenticity.

## How It Works

1. Tink generates a signature using your webhook secret
2. Signature is sent in the `X-Tink-Signature` header
3. You verify the signature matches the payload

## Security

- Always verify signatures before processing webhooks
- Uses `:crypto.hash_equals/2` for constant-time comparison to prevent timing attacks
- Store webhook secret securely (environment variable)
- Reject webhooks with invalid signatures

## Examples

    # Verify a webhook signature
    body = request_body
    signature = request_headers["x-tink-signature"]
    secret = System.get_env("TINK_WEBHOOK_SECRET")

    case Tink.WebhookVerifier.verify_signature(body, signature, secret) do
      :ok ->
        # Signature is valid, process webhook
        process_webhook(body)

      {:error, :invalid_signature} ->
        # Reject the webhook
        {:error, "Invalid signature"}
    end

# `generate_signature`

```elixir
@spec generate_signature(String.t(), String.t()) :: String.t()
```

Generates a signature for a payload.

Useful for testing webhook handlers.

## Parameters

  * `payload` - Payload to sign (string)
  * `secret` - Webhook secret

## Returns

  Hexadecimal signature string

## Examples

    iex> payload = ~s({"type":"credentials.updated"})
    iex> secret = "webhook_secret_123"
    iex> Tink.WebhookVerifier.generate_signature(payload, secret)
    "a1b2c3d4e5f6..."

# `test_webhook?`

```elixir
@spec test_webhook?(map()) :: boolean()
```

Checks if a webhook is a test webhook.

Tink may send test webhooks to verify endpoint configuration.

## Examples

    iex> Tink.WebhookVerifier.test_webhook?(%{"type" => "test"})
    true

    iex> Tink.WebhookVerifier.test_webhook?(%{"type" => "credentials.updated"})
    false

# `validate_payload`

```elixir
@spec validate_payload(map()) :: :ok | {:error, atom()}
```

Validates webhook payload structure.

Checks if the webhook has required fields.

## Parameters

  * `payload` - Parsed webhook payload (map)

## Returns

  * `:ok` - Payload is valid
  * `{:error, reason}` - Payload is invalid

## Examples

    iex> payload = %{"type" => "credentials.updated", "data" => %{}}
    iex> Tink.WebhookVerifier.validate_payload(payload)
    :ok

    iex> Tink.WebhookVerifier.validate_payload(%{})
    {:error, :missing_type}

# `verify_signature`

```elixir
@spec verify_signature(String.t(), String.t() | nil, String.t()) ::
  :ok | {:error, :invalid_signature | :missing_signature}
```

Verifies a webhook signature.

Uses `:crypto.hash_equals/2` for constant-time comparison to prevent timing attacks.

## Parameters

  * `payload` - Raw webhook payload (string)
  * `signature` - Signature from `X-Tink-Signature` header
  * `secret` - Your webhook secret

## Returns

  * `:ok` - Signature is valid
  * `{:error, :invalid_signature}` - Signature is invalid
  * `{:error, :missing_signature}` - No signature provided

## Examples

    iex> payload = ~s({"type":"credentials.updated"})
    iex> secret = "webhook_secret_123"
    iex> signature = Tink.WebhookVerifier.generate_signature(payload, secret)
    iex> Tink.WebhookVerifier.verify_signature(payload, signature, secret)
    :ok

    iex> Tink.WebhookVerifier.verify_signature(payload, "invalid", secret)
    {:error, :invalid_signature}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
