Skip to main content

Webhook security

Signature verification (Ed25519)

Webhook authenticity and integrity are ensured using Ed25519 asymmetric signatures.

Key material from TechWolf

For each webhook endpoint, TechWolf provides:
  • Public key (Ed25519) - used by you to verify webhook signatures
Private keys are held only by TechWolf and securely managed.

Signed message format

The signature is computed over:
timestamp:tenant:event_id:request_body
The result is sent in the X-Signature-V1 header:
X-Signature-V1: <hex-signature-1>,<hex-signature-2>
TechWolf supports non-breaking key rotation. During a rotation window, the same request may be signed with multiple active private keys, so X-Signature-V1 can contain several signatures. Validate the webhook by verifying that at least one signature matches using any of the currently active public keys. This allows key updates without downtime.

Security responsibilities

You must:
  • Verify the Ed25519 signature using the provided public key
  • Validate timestamp freshness to prevent replay attacks (e.g. reject requests where the X-Signature-Timestamp is older than 5 minutes)
  • Reject invalid or stale requests with a 401 response

Python example: signature verification

from nacl.signing import VerifyKey
from nacl.exceptions import BadSignatureError

# Public key provided by TechWolf (hex-encoded)
PUBLIC_KEY = "TECHWOLF_PUBLIC_KEY_HEX"

verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY))

signatures = request.headers["X-Signature-V1"]
timestamp = request.headers["X-Signature-Timestamp"]
tenant = request.headers["X-Tenant"]
event_id = request.headers["X-Event-Id"]
body = request.data.decode("utf-8")

# TechWolf signature payload format:
# <timestamp>:<tenant>:<event_id>:<request_body>
message = f"{timestamp}:{tenant}:{event_id}:{body}".encode("utf-8")

# X-Signature-V1 may contain multiple comma-separated signatures.
# The request is valid if at least one signature matches.
for signature in signatures.split(","):
    try:
        verify_key.verify(
            message,
            bytes.fromhex(signature.strip()),
        )
        break
    except BadSignatureError:
        continue
else:
    abort(401, "invalid request signature")

OAuth2 endpoint authentication (optional)

In addition to signature verification, TechWolf can authenticate webhook requests to your endpoint using OAuth2. This protects against unauthorised callers reaching your endpoint. OAuth2 is optional and does not replace signature verification; authenticity and integrity are always guaranteed by Ed25519.

Request format

When OAuth2 is enabled, TechWolf sends an access token in the Authorization header:
Authorization: Bearer <access_token>

Enabling OAuth2

To enable OAuth2 for webhook delivery, you must provide:
ItemDescription
OAuth2 Token URLYour token endpoint
Grant typeclient_credentials
Client credentials for TechWolfclient_id, client_secret
ScopeAs required by your endpoint
Additional parametersAny other fields your token endpoint expects (e.g. audience, resource, or custom parameters). Provide name and value per parameter.

Custom headers (optional)

You can configure custom headers that TechWolf will send with every webhook request to your endpoint (e.g. for routing or internal auth). The standard headers (including signature headers) are always sent; custom headers are added on top.