Module: Recurly::Webhooks

Defined in:
lib/recurly/webhooks.rb

Constant Summary collapse

DEFAULT_TOLERANCE =
5 * 60 * 1000

Class Method Summary collapse

Class Method Details

.verify_signature(header, secret, body, tolerance: DEFAULT_TOLERANCE) ⇒ Object

Verify webhook signature

Examples:

begin
  Recurly::Webhooks.verify_signature(header,
                                     ENV['WEBHOOKS_KEY'],
                                     request.body)
rescue Recurly::Errors::SignatureVerificationError => e
  puts e.message
end

Parameters:

  • header (String)

    recurly-signature header from request

  • secret (String)

    Shared secret for notification endpoint

  • body (String)

    Request POST body

  • tolerance (Integer) (defaults to: DEFAULT_TOLERANCE)

    Allowed notification time drift in milliseconds



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/recurly/webhooks.rb', line 20

def self.verify_signature(header, secret, body, tolerance: DEFAULT_TOLERANCE)
  s_timestamp, *signatures = header.split(",")
  timestamp = Integer(s_timestamp)
  now = (Time.now.to_f * 1000).to_i

  if (now - timestamp).abs > tolerance
    raise Recurly::Errors::SignatureVerificationError.new(
      "Notification (#{Time.at(timestamp / 1000.0)}) is more than #{tolerance / 1000.0}s out of date"
    )
  end

  expected = OpenSSL::HMAC.hexdigest("sha256", secret, "#{timestamp}.#{body}")

  unless signatures.any? { |s| secure_compare(expected, s) }
    raise Recurly::Errors::SignatureVerificationError.new(
      "No matching signatures found for payload"
    )
  end
end