# Securing Your Webhooks: HMAC vs OAuth (/docs/guides/tutorials/securing-your-webhooks-hmac-vs-oauth)


## The scenario [#the-scenario]

You expose: `POST https://api.yourproduct.com/integrations/verdocs/events. `A third party discovers the endpoint and sends a fake “envelope completed” event. Your backend trusts the payload and closes a deal automatically.

Or your security team mandates OAuth, but your gateway only supports static API-key validation and cannot validate rotating bearer tokens.

This guide focuses specifically on **authenticating inbound webhook requests** from Verdocs to your infrastructure.

It does **not** replace:

* HTTPS/TLS
* idempotency protection
* payload validation
* organization authorization checks

***

## What Verdocs sends on the wire [#what-verdocs-sends-on-the-wire]

Webhook deliveries are typically sent as:

* `POST` requests
* `Content-Type: application/json`
* JSON payloads containing fields such as:
* `id`
* `event`
* `created_at`
* `organization_id`
* `data`

Always treat the Webhooks reference as the source of truth for exact payload structures and field names.

### Delivery expectations [#delivery-expectations]

Webhook handlers should respond quickly - typically within a few seconds.

Long-running tasks should be queued asynchronously after validation succeeds. Your endpoint should acknowledge receipt with a `2xx` response once the request has been authenticated and accepted.

Do not block the response while downstream systems finish processing.

***

## Option A - HMAC (shared secret) [#option-a---hmac-shared-secret]

### Mental model [#mental-model]

Verdocs and your application share a secret. Each webhook delivery includes a cryptographic signature derived from the payload. Your server recomputes the signature and verifies it matches. If an attacker does not know the secret, they cannot forge a valid request.

***

### Configuration [#configuration]

In the Verdocs webhook configuration:

* choose the HMAC authentication method
* configure a shared secret

Store the same secret securely in your own infrastructure.

***

### Verification flow [#verification-flow]

#### 1. Read the raw request body [#1-read-the-raw-request-body]

Read the request payload before modifying or reparsing it. Many integrations accidentally break verification by changing whitespace or serialization order before hashing.

#### 2. Read the signature header [#2-read-the-signature-header]

Verdocs sends a signature in: `x-webhook-signature`.

#### 3. Recompute the HMAC [#3-recompute-the-hmac]

Use the documented signing algorithm (currently SHA-256 for modern integrations).

#### 4. Compare securely [#4-compare-securely]

Use a constant-time comparison function to avoid timing attacks.

Reject requests when:

* the header is missing
* the signature does not match
* the payload is malformed

***

### Important implementation detail [#important-implementation-detail]

The signature is tied to the event payload Verdocs defines in the webhook contract - not necessarily the entire outer request wrapper.

Always implement verification against the exact signing input documented in the Webhooks reference. If your computed hash disagrees with the reference behavior, the reference documentation is the contract.

***

### Operational guidance [#operational-guidance]

#### Rotate secrets periodically [#rotate-secrets-periodically]

Use the documented secret rotation workflow and coordinate deployment timing carefully.

#### Treat secrets like passwords [#treat-secrets-like-passwords]

Never log secrets, commit them to source control, or expose them client-side

***

### When HMAC fits well [#when-hmac-fits-well]

HMAC is usually a good fit when:

* your deployment model is simple
* you want minimal infrastructure dependencies
* you do not already operate OAuth token issuance infrastructure
* your gateways validate static secrets more easily than bearer tokens

***

## Option B - OAuth client credentials [#option-b---oauth-client-credentials]

### Mental model [#mental-model-1]

Verdocs acts as an OAuth client to your authorization server. Before sending webhooks, Verdocs requests an access token using the `client_credentials` grant.

Verdocs then calls your webhook endpoint using: `Authorization: Bearer &lt;token>`

***

### Configuration [#configuration-1]

Webhook settings include:

| Field            | Purpose                                         |
| ---------------- | ----------------------------------------------- |
| `token_endpoint` | Your OAuth token endpoint                       |
| `client_id`      | OAuth client ID issued to Verdocs               |
| `client_secret`  | OAuth client secret issued to Verdocs           |
| `scope`          | Optional scope value if required by your issuer |

The token request is typically sent as: `application/x-www-form-urlencoded`, using: `grant_type=client_credentials`.

Always confirm exact token request behavior against the current Webhooks reference if your OAuth provider has strict requirements.

***

### Verification flow [#verification-flow-1]

#### 1. Validate the bearer token [#1-validate-the-bearer-token]

Use your normal API token validation path:

* JWT signature verification
* token introspection
* API gateway enforcement
* opaque token lookup

#### 2. Verify audience or scope [#2-verify-audience-or-scope]

Ensure the token is intended for:

* the correct API
* the correct route
* the expected integration audience

#### 3. Reject invalid requests [#3-reject-invalid-requests]

Reject requests with:

* missing authorization headers
* expired tokens
* invalid signatures
* insufficient scopes

***

### Token reuse behavior [#token-reuse-behavior]

Verdocs may reuse tokens until expiration if your token response includes standard expiry metadata such as:

* `expires_in`
* `exp`

Short-lived access tokens are recommended for webhook integrations.

Very long-lived bearer tokens reduce the security benefits of OAuth mode.

***

### When OAuth fits well [#when-oauth-fits-well]

OAuth is often preferred when:

* your organization already standardizes on OAuth2
* security teams require centralized token issuance and auditing
* your API platform already validates JWTs or opaque bearer tokens
* you need audience, scope, or claims-based authorization

***

## Choosing between them [#choosing-between-them]

| Question                                         | Better fit |
| ------------------------------------------------ | ---------- |
| Do we already issue OAuth clients to partners?   | OAuth      |
| Do we want the simplest implementation possible? | HMAC       |
| Does our gateway only understand static secrets? | HMAC       |
| Do we require aud/scope-based authorization?     | OAuth      |

Many teams start with HMAC and later migrate to OAuth as platform maturity increases.

Both are supported webhook authentication patterns.

***

## “None” is technically possible (but risky) [#none-is-technically-possible-but-risky]

Some environments permit webhook endpoints with no additional authentication beyond HTTPS.

That may be acceptable for temporary development tunnels or local testing.

For production systems, assume URLs eventually leak and enable either:

* HMAC authentication
* OAuth authentication

***

## Commonly asked questions [#commonly-asked-questions]

### Should we validate `organization_id`? [#should-we-validate-organization_id]

Yes. Authentication proves who sent the request. Your application still needs authorization logic to ensure the event belongs to a recognized tenant or customer.

***

### Is IP allowlisting enough? [#is-ip-allowlisting-enough]

IP allowlists should be treated as defense in depth, not the primary security mechanism. Cryptographic verification and bearer-token validation fail closed much more reliably.

***

### Should webhook handlers be idempotent? [#should-webhook-handlers-be-idempotent]

Strongly recommended. Retries and duplicate deliveries can occur. Use the webhook `id` or another stable event identifier to deduplicate processing.

***

### Can we subscribe to only certain events? [#can-we-subscribe-to-only-certain-events]

Yes. Webhook configurations allow selecting specific event types. In production, subscribing narrowly reduces load and operational surprises.

***

## Takeaway [#takeaway]

* **HMAC** uses a shared secret and request signature verification. It is operationally simple and works well for straightforward deployments.
* **OAuth client credentials** uses short-lived bearer tokens issued by your authorization server. It fits best when OAuth is already your organization’s standard for machine-to-machine authentication.

Both approaches secure inbound webhook traffic effectively when implemented correctly.

**Learn More:** [Webhooks](https://developers.verdocs.com/docs/reference/Rest-API/webhooks) · [Web SDK v6.6.0 - webhook authentication](https://developers.verdocs.com/docs/learn/whats-new/web-sdk-v6-6-0)
