Class: PurchaseKit::WebhookSignature

Inherits:
Object
  • Object
show all
Defined in:
lib/purchasekit/webhook_signature.rb

Overview

Verifies HMAC-SHA256 signatures on incoming webhooks.

The PurchaseKit SaaS signs all webhook payloads with your webhook secret. This class verifies those signatures to ensure webhooks are authentic.

Example:

PurchaseKit::WebhookSignature.verify!(
  payload: request.raw_post,
  signature: request.headers["X-PurchaseKit-Signature"],
  secret: PurchaseKit.config.webhook_secret
)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(payload:, signature:, secret:) ⇒ WebhookSignature

Returns a new instance of WebhookSignature.



20
21
22
23
24
# File 'lib/purchasekit/webhook_signature.rb', line 20

def initialize(payload:, signature:, secret:)
  @payload = payload
  @signature = signature
  @secret = secret
end

Instance Attribute Details

#payloadObject (readonly)

Returns the value of attribute payload.



18
19
20
# File 'lib/purchasekit/webhook_signature.rb', line 18

def payload
  @payload
end

#secretObject (readonly)

Returns the value of attribute secret.



18
19
20
# File 'lib/purchasekit/webhook_signature.rb', line 18

def secret
  @secret
end

#signatureObject (readonly)

Returns the value of attribute signature.



18
19
20
# File 'lib/purchasekit/webhook_signature.rb', line 18

def signature
  @signature
end

Class Method Details

.verified_payload(payload:, signature:, secret:) ⇒ Object



55
56
57
# File 'lib/purchasekit/webhook_signature.rb', line 55

def verified_payload(payload:, signature:, secret:)
  new(payload: payload, signature: signature, secret: secret).verified_payload
end

.verify!(payload:, signature:, secret:) ⇒ Object



51
52
53
# File 'lib/purchasekit/webhook_signature.rb', line 51

def verify!(payload:, signature:, secret:)
  new(payload: payload, signature: signature, secret: secret).verify!
end

Instance Method Details

#verified_payloadObject

Verify the signature and return the parsed JSON payload.



45
46
47
48
# File 'lib/purchasekit/webhook_signature.rb', line 45

def verified_payload
  verify!
  JSON.parse(payload, symbolize_names: true)
end

#verify!Object

Verify the signature. Raises SignatureVerificationError if invalid.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/purchasekit/webhook_signature.rb', line 27

def verify!
  if secret.blank?
    raise SignatureVerificationError, "webhook_secret must be configured"
  end

  if signature.blank?
    raise SignatureVerificationError, "Missing signature"
  end

  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, payload)
  unless ActiveSupport::SecurityUtils.secure_compare(signature, expected)
    raise SignatureVerificationError, "Invalid signature"
  end

  true
end