Securing Your Endpoints

There are two separate security jobs for any webhook endpoint:

  1. control who is allowed to reach the endpoint at all
  2. verify that a request claiming to be from YunoJuno is genuine

You should do both.

YunoJuno supports two practical ways to protect the endpoint itself:

  • API headers
  • HTTP Basic Auth

We recommend API headers.

Why we recommend API headers

API headers are usually the better operational choice because they:

  • avoid putting credentials into the URL, as URLs appear in user interfaces and can get shared, leading to unintentional leaks
  • are easier to rotate cleanly
  • work better with reverse proxies, API gateways, and load balancers
  • are usually easier to inspect and manage in production

A common pattern is a shared secret header such as:

Authorization: Bearer <your-shared-token>

or a dedicated custom header such as:

X-Webhook-Auth: <your-shared-token>

HTTP Basic Auth

HTTP Basic Auth is also supported if your infrastructure expects it.

It is simple and widely understood, but it is usually less flexible than API headers and can be awkward to rotate if the credential is embedded into the endpoint URL or managed in multiple places.

Use it if your environment requires it, not because it is the preferred default.

Endpoint authentication is not enough on its own

Header auth or Basic Auth only controls whether a request can reach your service.

You should still verify the webhook signature on every request. Signature verification is what proves:

  • the request really came from YunoJuno
  • the body was not tampered with in transit
  • the timestamp is recent enough to reduce replay risk

Signature headers

Each webhook request includes three signature-related headers:

  • svix-id
  • svix-timestamp
  • svix-signature

YunoJuno also gives you a signing secret for each endpoint in the webhook portal. Keep that secret server-side.

Verification rules

To verify a request:

  1. read the raw request body exactly as received
  2. build the signed content as {svix-id}.{svix-timestamp}.{raw_body}
  3. calculate an HMAC-SHA256 signature using your endpoint signing secret
  4. compare your calculated signature against the values in svix-signature
  5. reject the request if the timestamp is too old for your tolerance window

Raw body matters

Do not parse and re-serialize the JSON before verification.

Signature verification must use the exact raw body bytes that arrived over HTTP. If your framework automatically parses JSON for you, make sure the webhook route reads the raw body before any transformation happens.

Manual verification shape

This is the core logic:

signed_content = svix-id + "." + svix-timestamp + "." + raw_body
expected_signature = base64(hmac_sha256(secret, signed_content))

The svix-signature header can contain multiple signatures. Your calculated value only needs to match one of them.

Timestamp checks

You should also check that svix-timestamp is within a small tolerance window of your current system time.

That protects you against replay of old requests. A five minute tolerance is a sensible default for most integrations.

Response handling

If authentication or signature verification fails, return a non-2xx response and log the reason internally.

If verification succeeds, acknowledge the request with a 2xx response as soon as the event has been safely accepted by your system. Do not hold the HTTP response open while long-running downstream work completes.

For most integrations, the best setup is:

  • HTTPS endpoint
  • API header authentication
  • signature verification on every request
  • idempotent event handling keyed by the webhook message ID
  • fast 2xx acknowledgement once the message is safely queued or persisted

That combination is the most robust pattern for both security and delivery reliability.