Skip to main content
Every webhook request is signed, so you can prove that it comes from AllRide and that the body was not changed on the way. Verify the signature on every request before you parse or act on the body, and reject requests that fail with 400.

Signature scheme

Each request carries one header:
  • t is the time of signing in Unix seconds (UTC).
  • Each webhook endpoint has two secrets, firstSecret and secondSecret. s1 is computed with the first secret and s2 with the second.
  • Each signature is the lowercase hexadecimal HMAC-SHA256 of the string <raw body>.<t>: the exact request body bytes as received (before any JSON parsing or re-serialisation), a dot, then the value of t. The key is the secret’s UTF-8 bytes.
A request is authentic when either s1 or s2 matches the HMAC computed with either of the secrets you have stored. Compare in constant time. Protect against replayed requests by rejecting a t that is too far from your clock. We recommend a tolerance of 5 minutes. Replays that you start from the delivery log are signed again with a fresh t, so they pass this check. Retries and replays keep the body’s event.id, so deduplicate on it after the signature check. Both secrets are shown only once: when you create the endpoint (both) and when you rotate one of them (the new one). AllRide never shows them again, not in the dashboard and not in the delivery log, which records only the header value that was sent.

Verify with a library

AllRide does not publish an SDK or a verification library. Every mainstream language ships HMAC-SHA256 and a constant-time comparison in its standard library, so the verification is about 20 lines; the handlers below need nothing else. If your web framework parses JSON before your code runs, configure the webhook route to give you the raw body (for example express.raw({ type: "application/json" }) in Express, request.get_data() in Flask, receiveText() in Ktor): a body that was parsed and serialised again no longer matches the signature.

Verify manually

Each handler below reads the raw body, verifies s1 or s2 against the secrets in the environment variables WEBHOOK_FIRST_SECRET and WEBHOOK_SECOND_SECRET (during a rotation one of them may be unset), answers 204 on success and 400 on failure. Process the event after you have acknowledged it.
To compute a signature by hand, for example while debugging, use openssl on a file that holds the exact body:
The output must equal s1 (and the same command with WEBHOOK_SECOND_SECRET must equal s2). Make sure the file has no trailing newline that was not in the request.

Test vector

Use these documentation values to test your implementation. They are not real secrets. Raw body (1476 bytes, UTF-8, no trailing newline; the two € signs are multi-byte characters):
Expected header:
A correct implementation:
  • accepts the request with both secrets configured;
  • accepts it with only the second secret configured (the situation during a rotation of the first secret);
  • rejects it when one byte of the body changes;
  • rejects it when your clock is more than 5 minutes away from t (set “now” to 1793610900 when you run the vector).
Check your handler against this vector before you go live: it must accept the request, and reject it when you change one byte of the body.

Secret rotation

The two secrets let you rotate without dropping a single webhook, because AllRide signs every request with both:
1

Rotate the first secret

Call Rotate the first secret (or use the developer dashboard). The response shows the new firstSecret once. From now on, s1 uses the new secret and s2 still uses the unchanged second secret, so your receiver keeps accepting requests through s2.
2

Update your receiver

Store the new first secret and deploy. Your receiver now accepts s1 again.
3

Rotate the second secret

Call Rotate the second secret, store the new secondSecret and deploy again.
Rotation needs manage-webhooks (and a recent sign-in for dashboard users). If a rotation response gets lost, a retry with the same Idempotency-Key returns the endpoint with the secret set to null; rotate that slot again. Rotate immediately if you suspect a secret has leaked.