Receive webhooks
Have your project call your server when a person is created, a session ends or a sign-in fails, and verify that each call is genuine.
A webhook is an HTTP call from your project to your server when something happens. Use webhooks to keep another system current: create a workspace when a person is created, or close a person's sessions elsewhere when they are suspended.
Before you begin
You need:
- An
httpsURL on your server. The URL must be public: a webhook cannot be pointed at a private or internal address. - A handler at that URL that can read the raw request body and answer within 10 seconds.
- Access to Integrations > Connections in the AuthFI console.
Register the webhook
In the console, open Integrations > Connections and choose Connect something. Under Webhooks, choose Custom webhook. The Register a webhook dialog opens.
Choose Register.
Store the signing secret
The dialog now shows the signing secret, under the title Its signing secret, shown once. Copy the secret and store it with your server's other secrets. The signing secret is how you tell a genuine call from a forged one.
Choose I've stored it. The webhook appears as a card on the Connections tab.
Verify the signature
Every call carries a signature in the X-AuthFI-Signature-256 header. The signature is an HMAC-SHA256, keyed with your signing secret, of three parts joined together: the value of X-AuthFI-Timestamp, a dot, and the exact body you received.
Compute the same value on your server and compare the two.
import { createHmac, timingSafeEqual } from "node:crypto";
// `rawBody` is the bytes as received, before any JSON parsing.
export function genuine(rawBody, headers, secret) {
const timestamp = headers["x-authfi-timestamp"];
const expected = "sha256=" + createHmac("sha256", secret).update(`${timestamp}.`).update(rawBody).digest("hex");
const given = headers["x-authfi-signature-256"] ?? "";
return expected.length === given.length && timingSafeEqual(Buffer.from(expected), Buffer.from(given));
}secret is the signing secret you stored. headers are the request headers, and the body is the bytes as they arrived.
Check the signature before you do anything else. Reject a call whose signature does not match, and reject a timestamp more than a few minutes old.
Answer within 10 seconds
Answer with any 2xx status within 10 seconds. Do the work afterwards: accept the call, queue it, and return.
Check that it works
Cause one of the events you chose. For example, with Group member added selected, add a person to a group in the console.
Your server receives a POST whose X-AuthFI-Event header is group.member_added, and your signature check passes.
Events
What your server receives
Each call is a POST with a JSON body.
{
"id": "9b2f6c1e-...",
"event": "group.member_added",
"timestamp": "2026-10-10T09:14:07Z",
"data": {
"actor": "user:[email protected]",
"subject": "user:[email protected]",
"resource_type": "group",
"resource_id": "engineering"
}
}The call carries these headers:
How deliveries are retried
Your answer decides whether AuthFI sends the call again.
A retry carries the same X-AuthFI-Delivery as the first attempt. Store the IDs you have handled, and ignore a delivery you have already handled.
Order of deliveries
Deliveries can arrive in any order. When order matters, sort by timestamp in the body.
Pause or remove a webhook
On Integrations > Connections, open the Connections tab and find the webhook's card.
- To stop deliveries for a while, choose Pause and confirm with Pause deliveries. To start them again, choose Resume and confirm with Resume deliveries.
- To remove the webhook, choose Disconnect and confirm with Disconnect.