Overview
Authentication webhooks are HTTP endpoints you implement to control user access in Ditto applications. When a client device attempts to authenticate, Ditto forwards the authentication request to your webhook, which validates the user’s credentials and returns their permissions. To verify the request is legitimately coming from a Ditto system, Ditto may optionally include aditto-signature authentication header with every webhook request.
This header contains everything your webhook server needs to independently verify that the request is both legitimate (truly from Ditto) and fresh (not a replay attack).
See the Signature Algorithm section below for details on how signatures are computed.
Your webhook server uses the information in this header to perform verification.
By recomputing the signature using your shared secret and comparing it with the provided signatures, your server can confirm:
- Authenticity: The request genuinely originates from Ditto, not an impersonator
- Integrity: The payload hasn’t been modified since Ditto signed it
- Freshness: The timestamp is recent (typically within 5 minutes), preventing replay attacks
Signature verification
Webhook signature is computed using HMAC-SHA256. Ditto concatenates the timestamp with the raw request body, hashes this payload using a base64-decoded shared secret key, and encodes the output as hexadecimal. The following table breaks down each component of this process:| Component | Description |
|---|---|
| Secret | 128 bytes (1024 bits) of cryptographically secure random data, base64-encoded (RFC 4648) |
| Payload | Timestamp concatenated with raw request body: <timestamp>.<raw_body> |
| Algorithm | HMAC-SHA256 hash of the payload using the decoded secret |
| Output Encoding | Hexadecimal representation of the HMAC output |
ditto-signature header has this format:
t=<timestamp>- Unix timestamp in UTC when the request was signed (seconds since epoch)v1=<signature>- HMAC-SHA256 signature(s) in hexadecimal format
During secret rotation, Ditto can include multiple
v1= signatures in the header, one for each active secret.
This allows zero-downtime rotation: your endpoint can validate with either the old or new secret during the transition period.Manage Secrets
This section covers the complete lifecycle of webhook secrets: creating new secrets, listing active secrets, and deleting old or compromised secrets. You can manage secrets either through the Ditto Portal’s web interface or programmatically via the HTTP API. Webhook secrets have three timestamp fields that control their lifecycle:| Field | Type | Description |
|---|---|---|
notBefore | RFC 3339 DateTime | Secret becomes valid at this time |
notAfter | RFC 3339 DateTime | Secret expires at this time |
rotated | RFC 3339 DateTime or null | Timestamp when secret was marked for rotation (null if active) |
Add a New Secret
Webhook signatures are disabled by default. To enable them, simply generate a webhook secret via the Ditto Portal or HTTP API. Once you create a secret, Ditto automatically starts including theditto-signature header in all webhook requests, allowing your server to validate request authenticity.
Using Ditto Portal:
Access Webhook Configuration
Go to Settings → Authentication → Webhook Providers.Click
⋮ next to your webhook provider to open the configuration dialog.To use the HTTP API, you’ll need an API key with appropriate permissions. See HTTP API Authentication for details on creating and managing API keys.
List Active Secrets
Using Ditto Portal: In the webhook configuration dialog, active secrets are displayed in the Signature Verification section with their validity period and status.
Delete Active Secrets
You can delete old secrets after completing rotation or if you need to revoke a compromised secret. Using Ditto Portal: Click the Delete button next to the secret you want to remove. A confirmation dialog will appear to prevent accidental deletion.
Rotate Active Secrets
Ditto supports zero-downtime secret rotation by allowing multiple secrets to be active simultaneously. When rotating webhook secrets, the old and new secrets have an overlap period where both are simultaneously valid and active. During this overlap, Ditto signs all webhook requests with both secrets (including multiplev1= signature entries in the header), and your endpoint only needs to successfully validate against one of the provided signatures.
This dual-signature approach allows you to incrementally update your webhook servers without any authentication failures.
You can deploy the new secret to your infrastructure gradually, verify it works, and only then remove the old secret, eliminating the risk of downtime during the transition.
Timeline explanation:
- Old Secret Valid Period: Secret is active from
notBeforeuntil the overlap begins - Overlap Period: Both secrets are active and accepted - no downtime
- New Secret Valid Period: New secret continues after old secret’s
notAfter
Step-by-Step Rotation Guide
Generate New Secret
Mark the old secret for rotation and generate a new one:Using Ditto Portal:


Or via the HTTP API:Response:
- Select the active secret and click Rotate Secret.
- Confirm the rotation. The current secret will remain valid until its expiration date.

- After rotation, both secrets are visible. The old secret is marked as Rotated and the new one as Active.

- Click the eye icon to reveal and copy the new secret immediately and store it securely.

Update Your Webhook Endpoint
Add the new secret to your webhook endpoint, keeping the old secret active (see implementation examples).
Wait for Transition Period
Keep both secrets active for at least 24-48 hours to ensure all in-flight requests complete and no cached configurations remain.
Remove Old Secret from Application
After the transition period, remove the old secret from your webhook endpoint configuration and redeploy.
Delete Old Secret from Ditto
Clean up by deleting the old secret.Using Ditto Portal:
Using the HTTP API:
Expired secrets are not automatically deleted: Ditto does not garbage collect expired secrets. While expired secrets are no longer used in the
ditto-signature header, they remain in internal storage until explicitly deleted. This design ensures that all secret management operations are user-initiated, giving you full control over your security configuration. It’s your responsibility to delete old or expired secrets when they’re no longer needed.- Select the old rotated secret and click Delete.
- Confirm the deletion.

Migration Path
In case you already have webhooks without signature verification, you can add security with zero downtime as follows:Generate Secret Without Enforcing Verification
Create a webhook secret via the Ditto Portal or HTTP API, but don’t start verifying signatures in your application yet.
Deploy Verification Code (Disabled)
Add the signature verification code to your application with a configuration setting that keeps verification disabled. Deploy this version.
Common Pitfalls
Here’s a list of common pitfalls you may encounter when implementing your own webhook signature validation.| Problem | Possible Cause | Solution |
|---|---|---|
| Signature never matches | Using parsed JSON body instead of raw bytes | Access raw request buffer before JSON parsing (see code examples) |
| Intermittent failures | Clock skew > 5 minutes between servers | Sync server clocks with NTP, increase tolerance if needed |
| Old signatures fail after rotation | Not handling multiple signatures in header | Parse ALL v1= entries from header, validate against all configured secrets |
| Base64 decoding errors | Using URL-safe base64 | Use standard RFC 4648 base64 |
| Constant validation errors after deployment | Forgot to update secret in environment | Double-check environment variables are updated and deployment picked them up |

