Authenticating zerohash Webhooks with OAuth 2.0

For platforms whose security policy requires an authenticated bearer token on inbound calls from zerohash. Covers how the flow works, what zerohash needs from you, and what to configure on your side. The security method is set by zerohash, not through the API. There is no API change to make.

1. Available security methods

zerohash offers four ways to authenticate an outbound webhook. One applies per platform.

Security methodWhat zerohash sends on each webhook
RSAx-zh-hook-rsa-signature-256, x-zh-hook-rsa-signature, x-zh-hook-timestamp
Shared Secretx-zh-hook-signature-256, x-zh-hook-signature, x-zh-hook-timestamp
OAuth 2.0 Client CredentialsAuthorization: Bearer <token>
OAuth 2.0 Client Credentials with RSAAuthorization: Bearer <token> plus the three RSA signature headers

RSA is the default and remains zerohash's recommendation. The OAuth 2.0 options exist where a bearer token is mandatory.

2. Which method fits your listener

If your webhook listener...Choose
verifies the payload signature onlyRSA
requires a bearer token onlyOAuth 2.0 Client Credentials
requires a bearer token and verifies the payload signatureOAuth 2.0 Client Credentials with RSA

OAuth 2.0 Client Credentials replaces payload signing. If your listener checks both, you need the combined method; tell zerohash during setup.

3. How the OAuth 2.0 flow works

Your identity provider (IdP) issues the token. zerohash is a client of it.

  1. You register zerohash as a client in your IdP and issue it a client_id.
  2. zerohash generates a dedicated key pair and gives you the certificate. You register it directly, or zerohash publishes it at a JWKS URL for your IdP to read. No client secret is involved: the private key never leaves zerohash and no shared secret travels over the wire.
  3. Before each delivery window, zerohash signs a short-lived JWT with that private key and exchanges it at your token endpoint for an access token. This is the JWT bearer client assertion flow, RFC 7523 (private_key_jwt), with grant_type=client_credentials.
  4. zerohash caches the token and refreshes it in the background, so your IdP sees one token request per lifetime rather than one per webhook.
  5. Every webhook for your platform carries that token as Authorization: Bearer <token>.

The assertion zerohash sends is signed RS256, carries a unique jti per request, and has a lifetime of five minutes or less.

4. What zerohash needs from you

Please provide all of the following, for each environment you will integrate with. Setup cannot begin until each is confirmed.

ItemWhy it is needed
Token endpoint URLWhere zerohash exchanges the signed assertion for an access token. Must be HTTPS. Provide the URL for each environment separately if they differ.
client_id issued to zerohashIdentifies zerohash at your IdP.
Resource URI or scopesADFS-based IdPs expect a resource parameter; others expect scopes. Tell us which your IdP requires, and the exact value.
Expected audiencezerohash defaults to your token endpoint URL with a trailing slash, which is what ADFS expects. Confirm this, or give the value your IdP validates against.
How zerohash's certificate is registeredEither you upload the certificate to your IdP directly, or your IdP reads it from a JWKS URL. Tell us which, and whether your IdP matches the key by certificate thumbprint (and in which case) or by x5t. This is the most common cause of a rejected token, so please be specific.
Access token lifetimeLets zerohash size its refresh interval correctly.
Whether your listener also verifies the payload signatureDetermines whether you receive the signature headers alongside the token.
Your webhook listener URLWhere zerohash delivers. Provide one per environment.
The events you want to receivezerohash configures your event subscriptions.
Confirmation that zerohash's egress IPs are allow-listedWithout this, deliveries time out before reaching your listener. Request the IP ranges from your zerohash contact for each environment.
The contact who will receive zerohash's public keysThe signing certificate, and the RSA public key if you are verifying signatures.

5. What to configure on your side

  • Register zerohash in your IdP and issue the client_id, resource or scopes.
  • Register zerohash's signing certificate, by direct upload or by reading the JWKS URL.
  • Allow-list zerohash's egress IPs for each environment on your webhook listener.
  • If you verify the payload signature, load the zerohash RSA public key for that specific environment. Each environment signs with its own key, so a key held for one will not verify traffic from another. Ask your zerohash contact for the key per environment.
  • Accept the token on every event. The token is issued per platform, so if you receive events at more than one URL, all of them carry the same token.

6. What to expect in operation

  • Deliveries fail closed. If zerohash cannot obtain a valid token, no webhook is sent. zerohash never falls back to an unauthenticated delivery.
  • Failed deliveries retry. A delivery that fails, including one blocked by a token problem, is retried on a backoff schedule spanning several minutes before it is set aside. A short outage on your IdP or listener is absorbed without data loss.
  • A rejected token is replaced automatically. If your listener returns 401, zerohash discards the cached token and fetches a new one. A burst of rejections produces a single token request, not one per webhook.
  • Token requests are infrequent. Expect roughly one per token lifetime per environment, not one per event.

7. Troubleshooting

What you seeLikely causeWhat to check
Your IdP rejects zerohash's token requestA mismatch in client_id, resource or audience, or your IdP cannot match the signing key to the certificateRe-confirm those values and how the certificate is registered, including thumbprint case or x5t
Your listener returns 401 and zerohash keeps retryingThe token is valid at the IdP but not accepted by the listener, or the payload signature cannot be verifiedConfirm the listener trusts tokens from that IdP client, and that you hold the environment's RSA public key if you verify signatures
No webhooks arrive at all, and no requests appear in your logszerohash's egress IPs are not allow-listed, or the listener URL on file is wrongConfirm the allow-list and the URL with your zerohash contact
Webhooks arrive without an Authorization headerThe platform is not yet switched to an OAuth 2.0 methodRaise it with your zerohash contact

Contact your zerohash representative to begin setup or to change the security method on an existing integration.