Skip to content

Webhooks

Authpipe supports webhooks in two directions:

  • Outbound — Authpipe sends events to your app (connection created, token refreshed, refresh failed, etc.)
  • Inbound — External providers send webhooks to Authpipe, which verifies and forwards them
const result = await authpipe.setWebhookConfig("https://yourapp.com/webhooks/authpipe");
console.log(result.webhook_url); // "https://yourapp.com/webhooks/authpipe"
console.log(result.secret); // "whsec_..." — save this securely

The response includes a secret for signature verification. Store it securely — it’s only returned once.

EventTrigger
installation.createdApp installed in external workspace
installation.updatedPermissions or tokens changed
installation.suspendedInstallation paused by provider
installation.deletedInstallation removed
connection.createdUser completes OAuth or credential stored
connection.refreshedToken silently refreshed
connection.failedRefresh or health check failed
connection.revokedUser or admin disconnected
connection.reauth_requiredToken expired, needs user action
connection.scopes_changedGranted scopes modified
connection.deletedConnection permanently removed
credential.storedNew credential encrypted and saved
credential.rotatedCredential rotated (API key, webhook secret)
webhook.receivedInbound provider webhook verified and processed

Authpipe signs outbound webhooks with HMAC-SHA256. Verify the signature using the secret from setWebhookConfig.

import crypto from "crypto";
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string,
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);
}
// In your webhook handler:
app.post("/webhooks/authpipe", (req, res) => {
const signature = req.headers["x-authpipe-signature"];
if (!verifyWebhookSignature(req.rawBody, signature, WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
const event = req.body;
switch (event.event_type) {
case "connection.created":
console.log("New connection:", event.data);
break;
case "connection.failed":
console.log("Connection needs attention:", event.data);
break;
}
res.status(200).send("OK");
});

Rotate the signing secret without downtime. After rotation, Authpipe supports both the old and new secrets during the transition.

const result = await authpipe.rotateWebhookSecret();
console.log(result.secret); // new secret — update your app

After rotation:

  • secret_1 = new secret (current)
  • secret_2 = old secret (still valid for verification)

Update your app to use the new secret, then both secrets will be valid until the next rotation.

const config = await authpipe.getWebhookConfig();
console.log(config.webhook_url); // your URL
console.log(config.has_secret_1); // true
console.log(config.has_secret_2); // true (if rotated at least once)
await authpipe.deleteWebhookConfig();

Some providers send webhooks to Authpipe (e.g., Slack events, GitHub webhooks). These arrive at:

POST https://api.authpipe.dev/webhooks/{provider}

Authpipe verifies the webhook signature using the signing_key on the provider config, processes the event, and emits a webhook.received event to your outbound webhook URL.

Set the provider’s signing/verification key on your provider config:

await authpipe.updateProviderConfig("pcfg_abc123", {
signing_key: "your-provider-signing-secret",
});

Query the event log to audit webhook delivery and credential lifecycle events.

const events = await authpipe.searchEvents({
filter: {
event_type: { eq: "connection.failed" },
},
sort: [{ field: "created_at", direction: "desc" }],
limit: 20,
});