Webhook Verification

The SDK provides utilities to verify webhook signatures, ensuring that incoming webhook payloads genuinely originated from Felloh.


Verifying Signatures

Felloh signs every webhook request with an HMAC-SHA256 signature sent in the X-Signature header. The SDK provides two methods to verify this signature:

  • Felloh::Webhook.verify_signature — returns true or false
  • Felloh::Webhook.verify_signature! — raises an error if invalid

Both use timing-safe comparison to prevent timing attacks.

Parameters

  • Name
    payloadrequired
    Type
    String
    Description

    The raw request body. Must not be parsed or modified — use the raw body as received.

  • Name
    signaturerequired
    Type
    String
    Description

    The value of the X-Signature header from the webhook request.

  • Name
    secretrequired
    Type
    String
    Description

    Your webhook signing secret from the Felloh dashboard.

Boolean Check

valid = Felloh::Webhook.verify_signature(
  payload: raw_request_body,
  signature: request.headers["X-Signature"],
  secret: "your-webhook-secret",
)

unless valid
  render json: { error: "Invalid signature" },
         status: :unauthorized
  return
end

# Process the webhook...

Assert (raises on failure)

begin
  Felloh::Webhook.verify_signature!(
    payload: raw_request_body,
    signature: request.headers["X-Signature"],
    secret: "your-webhook-secret",
  )
rescue Felloh::WebhookSignatureError
  render json: { error: "Invalid signature" },
         status: :unauthorized
  return
end

# Signature is valid, process the webhook...

Rails Example

When using Rails, access the raw request body via request.raw_post to prevent body parsing from modifying the payload.

Rails Webhook Controller

class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token

  def felloh
    Felloh::Webhook.verify_signature!(
      payload: request.raw_post,
      signature: request.headers["X-Signature"],
      secret: ENV["FELLOH_WEBHOOK_SECRET"],
    )

    event = JSON.parse(request.raw_post)
    Rails.logger.info "Webhook: #{event}"

    head :ok
  rescue Felloh::WebhookSignatureError
    head :unauthorized
  end
end