Webhook signature verification
To ensure secure communication between Adfin and your platform, webhook signature validation is essential. This guide outlines how to generate the necessary security credentials, including a signature digest key and an authentication method, before creating a webhook.
## Prerequisites
- You have set up webhooks for your app by subscribing to the webhook endpoint.
Step 1: Generate the webhook signature digest key
Before creating a webhook, you need to generate a signature digest key. This key will be used to validate the HMAC signature in each incoming webhook request, confirming the request’s authenticity and integrity.
curl -X PUT "https://staging.adfin.com/api/apps/{client_id}/webhooks/digest"
Explanation
- URL: Replace {client_id} with the unique
client_id
of your app. - Response: This request will return a secret key that should be securely stored and used to validate incoming webhook signatures. Make sure this key is handled and stored with strict security measures.
Response example
{
"secretKey": "_4ATIyq0Y8LyOGG_oxOXj8_9YqoGf64i1fmMPADeJkk_"
}
Step 2: Configure authentication for the webhook
You need to set up an authentication method for the webhook to ensure that only requests with valid credentials are accepted by your platform. Adfin supports several authentication types for webhook requests, including Basic Authentication, API Key Authentication, and OAuth Client Credentials.
Set the authentication method
curl -X PUT "https://staging.adfin.com/api/apps/{client_id}/webhooks/auth" \
-H "Content-Type: application/json" \
-d '{
"basicAuthentication": {
"username": "test",
"password": "Test4321"
},
"apiKeyAuthentication": {
"headerKey": "x-api-key",
"headerValue": "testApiKey"
}
}'
Explanation
- URL: Replace
{client_id}
with the unique client ID of your app. - Headers:
Content-Type
: Set toapplication/json
for JSON payloads.
- Request Body:
- basicAuthentication: Optional. Includes
username
andpassword
fields. - apiKeyAuthentication: Optional. Defines
headerKey
(e.g.,"x-api-key"
) andheaderValue
(the actual API key).
You can configure one or more of these methods, depending on your platform’s security requirements.
- basicAuthentication: Optional. Includes
Step 3: Verify incoming webhook requests
With the signature digest key and authentication method set up, you can now verify incoming webhook requests.
Webhook request headers
Every webhook request from Adfin includes these headers:
adfin-webhook-signature
: The HMAC signature of the payload.adfin-webhook-signature-timestamp
: The timestamp of when the request was generated.
Example Headers:
adfin-webhook-signature: H63TRZj13EwxnpRFg454yLH92bm3jZyv31=
adfin-webhook-signature-timestamp: 2024-10-01T09:01:35Z
Signature Verification Process
To verify the webhook, follow these steps:
- Concatenate: Combine the request payload (body) and the signature timestamp (
adfin-webhook-signature-timestamp
). - Generate HMAC: Use the signature digest key generated in Step 1 to create an HMAC SHA-256 hash of the concatenated data.
- Compare: Verify that the HMAC hash matches the
adfin-webhook-signature
header.
Java example for signature verification
Here’s a Java example to verify the signature:
private String generateVerificationSignature(String data, String key) {
final String algorithm = "HmacSHA256";
if (data == null || key == null) {
throw new IllegalArgumentException("data and secretKey must not be null");
}
try {
Mac hmacSHA256 = Mac.getInstance(algorithm);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
hmacSHA256.init(secretKeySpec);
byte[] dataBytes = hmacSHA256.doFinal(data.getBytes(StandardCharsets.UTF_8));
return new String(Base64.getEncoder().encode(dataBytes));
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException("Signature verification failed", e);
}
}
private boolean isSignatureValid(String signatureTimestampHeader, String signatureHeader, String eventPayload, String secretKey) {
String SEPARATOR = "||";
String data = signatureTimestampHeader + SEPARATOR + eventPayload;
String verificationSignature = generateVerificationSignature(data, secretKey);
return signatureHeader.equals(verificationSignature);
}
Handling authentication in webhook requests
Based on the configured authentication method:
- Basic Authentication: Check for
Authorization: Basic base64(username:password)
. - API Key Authentication: Verify that the request includes the correct header and value pair (e.g.,
x-api-key: testApiKey
).
Respond to the webhook
After validating the signature and authentication, respond to the webhook with a 2XX
status code if successful. If validation fails, respond with an appropriate error code (e.g., 400 Bad Request
or 401 Unauthorized
).
Security best practices
- Securely Store Credentials: Ensure both the signature digest key and authentication credentials are stored securely and rotated periodically.
- Log Events: Log webhook validation attempts and responses for audit and troubleshooting.
- Rate Limiting: Apply rate limiting to your webhook endpoint to prevent abuse.
Updated 29 days ago