Tink.WebhookVerifier (Tink v0.1.1)

Copy Markdown View Source

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

Summary

Functions

Generates a signature for a payload.

Checks if a webhook is a test webhook.

Validates webhook payload structure.

Verifies a webhook signature.

Functions

generate_signature(payload, secret)

@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?(arg1)

@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(payload)

@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(payload, signature, secret)

@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}