Webhook signature verification for Tink webhooks.
Tink signs webhook payloads using HMAC-SHA256 to ensure authenticity.
How It Works
- Tink generates a signature using your webhook secret
- Signature is sent in the
X-Tink-Signatureheader - You verify the signature matches the payload
Security
- Always verify signatures before processing webhooks
- Uses
:crypto.hash_equals/2for 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
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..."
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
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}
@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 fromX-Tink-Signatureheadersecret- 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}