Webhooks
Recevez des notifications HTTP en temps réel lorsque des événements d'authentification se produisent dans votre projet. Synchronisez les utilisateurs avec votre base de données, envoyez des e-mails de bienvenue ou déclenchez des workflows chaque fois que des utilisateurs s'inscrivent, se connectent ou sont bannis.
Que sont les webhooks ?
Un webhook est un rappel HTTP que votre serveur enregistre pour recevoir des notifications d'événements en temps réel. Au lieu d'interroger Authon pour vérifier si un utilisateur a été supprimé ou banni, Authon envoie proactivement une requête POST à votre URL au moment où l'événement se produit.
Utilisateur supprimé dans le tableau de bord Authon
→ Authon envoie POST /webhooks/authon
→ Votre serveur reçoit l'événement et supprime l'utilisateur de votre BDComment fonctionnent les webhooks
Lorsqu'un événement se produit dans votre projet Authon, l'API envoie une requête POST à votre point de terminaison enregistré avec une charge utile JSON. Chaque requête inclut un en-tête X-Authon-Signature avec un préfixe v1= — une signature HMAC-SHA256 calculée sur timestamp.body en utilisant votre secret de signature webhook. Vérifiez toujours cette signature avant de traiter l'événement.
Configurer un webhook
- 1Accédez à Tableau de bord → Webhooks → Ajouter un webhook
- 2Saisissez l'URL de votre point de terminaison — doit être accessible publiquement via HTTPS
- 3Sélectionnez les événements que vous souhaitez recevoir
- 4Copiez le secret de signature — affiché une seule fois, conservez-le en lieu sûr
- 5Définissez AUTHON_WEBHOOK_SECRET dans l'environnement de votre serveur
Types d'événements
| Événement | Déclencheur |
|---|---|
| user.created | Un nouvel utilisateur complète son inscription |
| user.updated | Le profil d'un utilisateur est mis à jour |
| user.deleted | Un compte utilisateur est définitivement supprimé |
| user.signin | Un utilisateur se connecte (e-mail ou OAuth) |
| user.signout | Un utilisateur se déconnecte |
| user.banned | Un utilisateur est banni par un administrateur |
| user.unbanned | Le bannissement d'un utilisateur est levé |
| session.created | Une nouvelle session est créée (connexion, rafraîchissement du jeton) |
| session.revoked | Une session est révoquée (déconnexion, révocation par l'administrateur) |
Format de la charge utile
Chaque charge utile webhook est un objet JSON avec une structure de niveau supérieur cohérente. Le champ data contient les détails spécifiques à l'événement.
{
"event": "user.created",
"data": {
"user": {
"id": "usr_abc123",
"email": "user@example.com",
"displayName": "Jane Doe",
"emailVerified": false,
"isBanned": false,
"publicMetadata": null,
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-15T10:30:00.000Z"
}
},
"timestamp": "2026-01-15T10:30:00.000Z"
}Pour les événementssession.*, le champ datainclut également un objet sessionavec l'id, l'adresse IP et le user agent.
Vérification de la signature
Chaque requête webhook contient un en-tête X-Authon-Signature au format v1=<hex_digest>. La signature est calculée en HMAC-SHA256 sur timestamp.rawBody en utilisant votre secret webhook. Comparez le résultat avec une égalité à temps constant.
| En-tête | Format | Description |
|---|---|---|
| X-Authon-Signature | v1={hmac_sha256} | Signature HMAC-SHA256 pour vérifier l'origine de la requête |
| X-Authon-Timestamp | ISO 8601 | Horodatage ISO 8601 de l'envoi de l'événement |
| X-Authon-Event | user.created | Le type d'événement (ex. user.created, session.revoked) |
json() d'Express re-sérialise le corps ce qui peut altérer les espaces et invalider la signature.Exemple Node.js
import { createHmac, timingSafeEqual } from "crypto";
import express from "express";
const router = express.Router();
function verifySignature(
rawBody: Buffer,
signature: string,
secret: string,
timestamp: string,
): boolean {
const payload = `${timestamp}.${rawBody.toString()}`;
const expected = createHmac("sha256", secret)
.update(payload)
.digest("hex");
const actual = signature.replace("v1=", "");
const expectedBuf = Buffer.from(expected, "hex");
const actualBuf = Buffer.from(actual, "hex");
return (
expectedBuf.length === actualBuf.length &&
timingSafeEqual(expectedBuf, actualBuf)
);
}
router.post(
"/webhooks/authon",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.headers["x-authon-signature"] as string;
const timestamp = req.headers["x-authon-timestamp"] as string; // ISO 8601
const eventType = req.headers["x-authon-event"] as string;
const webhookSecret = process.env.AUTHON_WEBHOOK_SECRET!;
if (!verifySignature(req.body, signature, webhookSecret, timestamp)) {
return res.status(401).json({ error: "Invalid signature" });
}
const { event, data } = JSON.parse(req.body.toString());
switch (eventType) {
case "user.created":
// Sync new user to your database
break;
case "user.deleted":
// Remove user from your database
break;
case "user.updated":
// Update user data
break;
case "user.banned":
// Revoke app-level access
break;
}
res.status(200).json({ received: true });
}
);
export default router;Utilisation du SDK
Le SDK@authon/node fournit un assistant de vérification intégré qui gère la comparaison à temps constant pour vous :
import { AuthonBackend } from "@authon/node";
const authon = new AuthonBackend(process.env.AUTHON_SECRET_KEY!);
router.post(
"/webhooks/authon",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.headers["x-authon-signature"] as string;
const timestamp = req.headers["x-authon-timestamp"] as string;
let event: Record<string, unknown>;
try {
event = authon.webhooks.verify(
req.body,
signature,
timestamp,
process.env.AUTHON_WEBHOOK_SECRET!,
);
} catch {
return res.status(401).json({ error: "Invalid signature" });
}
console.log("Verified event:", event.event);
res.json({ received: true });
}
);Politique de nouvelle tentative
Si votre point de terminaison retourne un code de statut non-2xx ou ne répond pas dans 10 secondes, Authon retente la livraison avec un backoff exponentiel. Maximum 3 tentatives au total.
| Tentative | Délai | Temps cumulé |
|---|---|---|
| Initiale | — | 0s |
| 1ère nouvelle tentative | 1 second | ~1s |
| 2ème nouvelle tentative | 2 seconds | ~3s |