Kobble
  1. Webhooks
Kobble
  • Introduction
  • API Fundamentals
    • Idempotency
    • Rate Limits
  • Authorization
    • Authorization
    • Get access token
      POST
  • Beneficiaries
    • List all beneficiaries
      GET
    • Get beneficiary by ID
      GET
    • Create beneficiary
      POST
    • Update beneficiary
      PUT
  • Cards
    • Cards API
    • Get all cards
      GET
    • Create a new card
      POST
    • Get card by ID
      GET
    • Update card status
      PATCH
    • Replace or renew card
      POST
    • Generate card secret
      POST
  • Card Programs
    • Card Programs API
    • Get all programs
      GET
    • Create a new program
      POST
    • Get program by ID
      GET
  • Clients
    • Clients API
    • Get all clients
    • Get client by ID
    • Create a new client
    • Update client status
  • Endusers
    • Endusers API
    • Get all endusers
    • Create a new enduser
    • Get enduser by ID
  • Transactions
    • Transactions API
    • Get all transactions
    • Create a transaction
    • Get transaction by ID
    • Create manual credit transaction
    • Create manual debit transaction
  • Wallets
    • Wallets API
    • Get all wallets
    • Create a new wallet
    • Get wallet by ID
    • Update wallet
  • Relays
    • Relays API
    • Create subscription
  • Webhooks
    • Webhooks API
    • Webhook Signature Verification
    • Get all webhooks
      GET
    • Create a webhook
      POST
    • Delete a webhook
      DELETE
  1. Webhooks

Webhook Signature Verification

Webhook Signature Verification Guide#

Overview#

All webhook requests from Kobble are cryptographically signed to ensure authenticity and integrity. You must validate the signature of every webhook request before processing it. This prevents unauthorized access and ensures the message hasn't been tampered with.

Why Validate Signatures?#

Signature validation provides:
Authentication: Confirms the request came from Kobble
Integrity: Ensures the payload hasn't been modified in transit
Security: Protects against spoofed or malicious requests
Never process webhook requests without validating their signatures.

Webhook Request Structure#

When Kobble sends a webhook, you receive a JSON payload with the following structure:

Headers#

x-amz-sns-message-id: Unique message identifier
x-amz-sns-message-type: One of Notification, SubscriptionConfirmation, or UnsubscribeConfirmation

Request Body (JSON)#

{
  "Type": "Notification",
  "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
  "TopicArn": "arn:aws:sns:us-east-1:123456789012:ExampleTopic",
  "Message": "{\"id\":\"d2e89f3f-48bd-4bfc-8fd0-2d6b8e7207c1\",\"type\":\"transaction-create\",\"entity_id\":\"...\",\"client_id\":\"...\",\"created_at\":\"2024-09-18T11:47:03.123Z\"}",
  "Timestamp": "2015-01-02T12:00:00.000Z",
  "SignatureVersion": "1",
  "Signature": "EXAMPLE1234567890...",
  "SigningCertURL": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-123456789.pem",
  "Subject": null,
  "UnsubscribeURL": "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&..."
}

Key Fields for Validation#

FieldDescription
TypeMessage type: Notification, SubscriptionConfirmation, or UnsubscribeConfirmation
MessageIdUnique identifier for this message
MessageThe actual webhook event data (JSON string)
TimestampISO 8601 timestamp when the message was created
SignatureVersionSignature algorithm version: "1" (RSA-SHA1) or "2" (RSA-SHA256)
SignatureBase64-encoded RSA signature
SigningCertURLHTTPS URL to download the public certificate

Signature Validation Process#

The validation process consists of four main steps:

Step 1: Validate Certificate URL#

Before downloading the certificate, verify the SigningCertURL is legitimate:
Requirements:
Must use HTTPS protocol
Must end with .pem extension
Hostname must match pattern: sns.[region].amazonaws.com (or .amazonaws.com.cn)
Example:
Security Note: Never download certificates from untrusted URLs. This validation prevents certificate injection attacks.

Step 2: Download the Certificate#

Download the public certificate from the validated URL:
Best Practice: Cache certificates with a reasonable TTL (e.g., 24 hours) to reduce download overhead. Certificates are rotated infrequently.

Step 3: Build the String to Sign#

Create the canonical string that was signed by constructing it from the message fields:
Process:
1.
Sort all field names alphabetically
2.
For each field, include it only if:
It's in the list of signable fields
It's not null or undefined
3.
Format each field as: FieldName\nFieldValue\n
Signable Fields:
Message
MessageId
Subject
SubscribeURL
Timestamp
Token
TopicArn
Type
Implementation:
Example Output:
Message
{"id":"123","type":"transaction-create"}
MessageId
95df01b4-ee98-5cb9-9903-4c221d41eb5e
Timestamp
2015-01-02T12:00:00.000Z
TopicArn
arn:aws:sns:us-east-1:123456789012:ExampleTopic
Type
Notification
Important Notes:
Field names are case-sensitive
Fields must be sorted alphabetically
Include the newline (\n) after both field name and value
Skip null and undefined values

Step 4: Verify the Signature#

Use the downloaded certificate to verify the signature:

Complete Implementation Examples#

Node.js/TypeScript#

Python#

Express.js Middleware Example#


Security Best Practices#

1. Certificate Caching#

Cache certificates with a reasonable TTL (24 hours) to reduce download overhead:

2. Timeout Protection#

Always set timeouts when downloading certificates:

3. Rate Limiting#

Implement rate limiting on your webhook endpoint to prevent abuse:

4. Comprehensive Logging#

Log validation failures for security monitoring:

5. Fail Securely#

Always reject requests if validation fails:
BAD: Processing without validation
GOOD: Validate first

Common Pitfalls and Solutions#

1. Case Sensitivity#

Problem: Field names are case-sensitive. Message ≠ message.
Solution: Always use exact field names as received.
Incorrect
Correct

2. Field Ordering#

Problem: Fields must be sorted alphabetically when building the string to sign.
Solution: Always sort keys before building the string:

3. Null Handling#

Problem: Null or undefined fields should be skipped.
Solution: Check for null/undefined before including:

4. Certificate URL Validation#

Problem: Downloading certificates from untrusted URLs.
Solution: Always validate the URL pattern before downloading:

5. Signature Version Support#

Problem: Only supporting one signature version.
Solution: Support both versions:

Testing Signature Validation#

Test with Valid Message#

Test Invalid Signature#

Test Invalid Certificate URL#


Troubleshooting#

Issue: Signature validation always fails#

Possible Causes:
1.
Incorrect string-to-sign construction
2.
Wrong signature algorithm
3.
Certificate download failure
4.
Base64 decoding error
Debug Steps:
1.
Log the string-to-sign to verify it matches expected format
2.
Verify signature version matches algorithm used
3.
Check certificate download succeeds
4.
Verify signature is properly base64-decoded

Issue: Certificate download times out#

Solution:
Implement certificate caching
Increase timeout (but not too much)
Add retry logic with exponential backoff

Issue: Validation works in test but fails in production#

Possible Causes:
1.
Different message structure in production
2.
Certificate caching issues
3.
Network/firewall blocking certificate downloads
Solution:
Compare test vs production message structure
Clear certificate cache
Check network connectivity to certificate URLs

Additional Resources#

Kobble Webhooks API Documentation
Webhook Best Practices
Kobble API Reference

Summary#

Signature validation is critical for webhook security. Always:
1.
Validate certificate URLs before downloading
2.
Build the string-to-sign correctly (alphabetical order, correct fields)
3.
Verify signatures using the correct algorithm (RSA-SHA1 or RSA-SHA256)
4.
Cache certificates to improve performance
5.
Log validation failures for security monitoring
6.
Reject requests with invalid signatures
By following this guide, you'll ensure your webhook integration is secure and reliable.
Modified at 2025-11-20 04:51:25
Previous
Webhooks API
Next
Get all webhooks
Built with