Advanced | Configuring Webhooks

Configure ADG webhooks to send credential match notifications and automate security response workflows.

Active Directory Guardian (ADG) supports webhooks that send credential match notifications to external systems, such as SIEM, SOAR, and ticketing platforms.

With webhooks, you can:

  • Send match notifications to external systems in real time.
  • Automatically create tickets in platforms such as ServiceNow.
  • Trigger playbooks in your SOAR and incident response workflows.
  • Combine webhook notifications with other remediation actions, such as disabling users or forcing password resets.

Availability: ADG 7.5.0 and later
Required role: Admin


How Webhooks Work

Setting up webhook notifications is a two-step process:

  1. Create a webhook under Settings → Webhooks to define the destination and authentication settings.
  2. Add the webhook to a Remediation Policy so it fires when a scan finds a match

The Remediation Policy determines which credential matches trigger a notification, such as Email + Exact Password. The webhook determines where that notification is sent.

Webhook delivery is one-way. ADG sends the notification and logs the result, but does not track what the receiving system does with it.


Managing Webhooks

Navigate to: Settings → Webhooks

From here, you can:

  • Create a new webhook
  • Edit an existing webhook
  • Delete a webhook (⚠️ cannot delete if it's in use by a Remediation Policy)

You can create as many webhooks as you need. For example, one for Splunk and another for Tines.


Creating a Webhook

  1. Click Add
  2. Complete the webhook fields (see below)
  3. Click Test Webhook to confirm connectivity (recommended)
  4. Click Save

Webhook Fields

FieldDescription
NameA unique, descriptive name used to identify the webhook when selecting it in a Remediation Policy. For example, for_splunk or for_tines.
URLThe destination endpoint that receives webhook notifications. Must be a valid HTTPS address.
Authentication TypeThe authentication method used to send requests to the destination. See Authentication Types below.
Custom Headers (JSON)Optional HTTP headers included with each request, entered as a JSON object. Example: {"X-Custom-Header": "value"}.
EnabledControls whether the webhook sends notifications. Disable this setting to pause notifications without deleting the configuration.

Important: Saved secrets are not displayed after they are entered. When editing a webhook, leave the credential and custom header fields blank to preserve existing values, or enter new values to replace them.


Authentication Types

ADG supports three authentication types:

  • None: No authentication headers are added to the request.
  • API Key: ADG sends your secret in the X-API-Key request header. Enter the key in the API Key field.
  • HMAC (recommended): Each request body is signed with a shared secret using HMAC-SHA256. The signature is sent in the webhook-signature header so your endpoint can verify the request is authentic and unaltered. Enter the secret in the Client Secret field.

Verifying HMAC Signatures

When HMAC is selected, ADG signs each delivery following the Standard Webhooks specification.

Every signed request includes these headers:

  • webhook-id: A unique message identifier, in the form msg_<uuid>
  • webhook-timestamp: When the request was signed, as a Unix timestamp (seconds since epoch, UTC)
  • webhook-signature: The signature, in the form v1,<base64-signature>

To verify a request at your endpoint:

  1. Read the webhook-id and webhook-timestamp headers and the raw, unmodified request body
  2. Build the signed content by joining them with periods: {webhook-id}.{webhook-timestamp}.{body}
  3. Compute an HMAC-SHA256 of that string, using your Client Secret as the key
  4. Base64-encode the result
  5. Compare your value to the portion of webhook-signature after v1, using a constant-time comparison
  6. Optional: Reject requests whose timestamp is outside an acceptable window (for example, older than 5 minutes) to prevent replay attacks
⚠️

Always verify against the raw request body. Many frameworks re-serialize JSON automatically, which breaks the signature.

💡

Match on the v1, scheme. Future versions may include multiple space-separated signatures in the header.

Python example

import base64, hashlib, hmac, time

def verify_adg_webhook(headers, raw_body: bytes, client_secret: str) -> bool:
    msg_id = headers["webhook-id"]
    timestamp = headers["webhook-timestamp"]

    if abs(time.time() - int(timestamp)) > 300:
        return False

    signed = f"{msg_id}.{timestamp}.".encode() + raw_body
    expected = base64.b64encode(
        hmac.new(client_secret.encode(), signed, hashlib.sha256).digest()
    ).decode()

    for sig in headers["webhook-signature"].split(" "):
        version, _, value = sig.partition(",")
        if version == "v1" and hmac.compare_digest(value, expected):
            return True
    return False

Node.js example

const crypto = require("crypto");

function verifyAdgWebhook(headers, rawBody, clientSecret) {
  const msgId = headers["webhook-id"];
  const timestamp = headers["webhook-timestamp"];

  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected = crypto
    .createHmac("sha256", clientSecret)
    .update(`${msgId}.${timestamp}.${rawBody}`)
    .digest("base64");

  return headers["webhook-signature"].split(" ").some((sig) => {
    const [version, value] = sig.split(",", 2);
    if (version !== "v1" || !value) return false;
    const a = Buffer.from(value);
    const b = Buffer.from(expected);
    return a.length === b.length && crypto.timingSafeEqual(a, b);
  });
}

Testing a Webhook

Before saving, click Test Webhook to send a sample request to the configured URL.

  • Uses the same authentication, signing, and custom headers as a real delivery
  • ADG confirms whether the test request was delivered successfully
  • Test requests are never retried, so you get immediate feedback

A test request sends this body instead of match data:

{
  "type": "webhook_test",
  "timestamp": "2026-06-19T14:05:00Z"
}

Tip: Configure your receiving endpoint to recognize "type": "webhook_test" so test requests don't generate tickets or security alerts.


Adding a Webhook to a Remediation Policy

Webhooks are triggered through ADG Remediation Policies.

  1. Create or edit a Remediation Policy
  2. Under Match Actions, select your webhook (listed as Webhook: )
  3. Click Save

You can select multiple webhooks within the same policy and combine them with other Match Actions, such as Disable User or Force Password Reset.

Important: Select every Match Action you want the policy to perform when a match is detected.


When a Webhook Fires

A webhook is sent once per matched account for each scan type the policy is assigned to: Manual, Scheduled, or Automatic

The following conditions do not trigger webhook notifications:

  • Accounts excluded by the Remediation Policy.
  • Email-only matches.
  • Webhooks with the Enabled setting turned off.

Webhook Payload Reference

Each match is delivered as an HTTP POST with a JSON body (Content-Type: application/json). The payload contains the same match data available in the CSV export.


Required Fields

The following fields are always included in the payload:

  • startDate: The scan's start date and time (ISO 8601)
  • runType: The type of scan that produced the match: Manual, Scheduled, or Automatic
  • samAccountName: The matched AD user's SAM account name
  • userPrincipalName: The matched user's User Principal Name (UPN)
  • displayName: The matched user's display name
  • emailAddress: The matched user's email address
  • spyCloudMatch: The match type (for example, Email + Exact Password, Dictionary, Fuzzy, IDLink, NIST)
  • status: The delivery status; always New for webhook deliveries
  • exposureCount: The number of exposures for NIST (Global Password) matches; 0 for all other match types
  • partialPassword: The first characters of the matched password for exact breach matches; an empty string for all other match types
  • exclusion: "true" or "false" (as a string) indicating whether the account was excluded by the policy

Conditional Fields

These fields may be null or empty when they don't apply:

  • spyCloudEntrySourceSite: The breach source site/title for the matched record
  • spyCloudEntrySourceDesc: The breach source description for the matched record
  • spyCloudEntrySourceId: The SpyCloud source identifier (catalog ID) of the matched breach record. Present only for breach-backed matches; omitted for Dictionary and NIST matches
  • exclusionDetails: The name of the exclusion rule that excluded the account, when exclusion is "true"
  • pwdLastSet: The date the user's AD password was last set

Example Payload

{
  "startDate": "2026-06-19T14:05:00Z",
  "runType": "Scheduled",
  "samAccountName": "jdoe",
  "userPrincipalName": "[email protected]",
  "displayName": "Jane Doe",
  "emailAddress": "[email protected]",
  "spyCloudMatch": "Email + Exact Password",
  "status": "New",
  "spyCloudEntrySourceSite": "Example Breach 2024",
  "spyCloudEntrySourceDesc": "Credentials exposed in the Example breach.",
  "spyCloudEntrySourceId": "12345",
  "exposureCount": 0,
  "partialPassword": "Pa$",
  "exclusion": "false",
  "exclusionDetails": "",
  "pwdLastSet": "2025-01-15T09:30:00Z"
}

Tip: Configure your receiving system to handle missing, null, or empty optional fields.


Delivery & Retries

Each delivery is an HTTP POST with a 30-second timeout. Return a 2xx response to acknowledge receipt. ADG automatically retries transient failures up to 3 times (4 attempts total):

  • Connection errors or timeouts
  • HTTP 429 (rate limit)
  • HTTP 5xx (server errors)

The first retry occurs after approximately 30 seconds, with increasing, randomized (jittered) delays between later attempts.

ADG does not retry:

  • Other HTTP 4xx responses (for example, 401 Unauthorized or 404 Not Found)
  • Requests sent with Test Webhook

Handling duplicate deliveries: Because failed requests may be retried, your receiving endpoint may occasionally receive duplicate notifications. When using HMAC authentication, use the webhook-id header to identify and deduplicate requests.

Transport is over HTTPS. The TLS version (1.2 or 1.3) is negotiated at runtime between the ADG host and the receiving server.


Webhook Logging

Every webhook attempt, success or failure, is recorded in the User Actions Log:

  • Action Taken: Webhook
  • Action Status: Completed or Failed

Importing a Configuration

Exported ADG configurations do not include webhook secrets.

After importing a configuration, edit each webhook and re-enter its authentication credentials. Otherwise, remediation actions that depend on those webhooks will fail.


Security Best Practices

The webhook payload includes user identity details and, for exact breach matches, a partial password. Treat it as sensitive data.

To protect webhook communications:

  • Use HMAC authentication and verify every signature
  • Enforce a timestamp tolerance to reject replayed requests
  • Store your API Key or Client Secret in a secrets manager
  • Restrict access to systems and logs that store webhook payloads
  • Rotate secrets periodically and when administrators with access leave

Did this page help you?