웹훅
프로젝트에서 인증 이벤트가 발생할 때 실시간 HTTP 알림을 수신하세요. 사용자가 가입하거나, 로그인하거나, 차단될 때마다 데이터베이스에 동기화하거나, 환영 이메일을 보내거나, 워크플로를 트리거하세요.
웹훅이란?
웹훅은 실시간 이벤트 알림을 수신하기 위해 서버에 등록하는 HTTP 콜백입니다. Authon에 폴링하여 사용자 삭제나 차단 여부를 확인하는 대신, Authon이 이벤트 발생 즉시 등록된 URL로 POST 요청을 능동적으로 전달합니다.
Authon 대시보드에서 사용자 삭제
→ Authon이 POST /webhooks/authon 전송
→ 서버에서 이벤트를 수신하여 DB에서 사용자 제거웹훅 작동 방식
Authon 프로젝트에서 이벤트가 발생하면, API가 JSON 페이로드와 함께 등록된 엔드포인트로 POST 요청을 보냅니다. 각 요청에는 v1= 접두사가 붙은 X-Authon-Signature 헤더가 포함됩니다 — 웹훅 서명 시크릿으로 timestamp.body를 HMAC-SHA256으로 서명한 값입니다. 이벤트를 처리하기 전에 항상 이 서명을 검증하세요.
웹훅 설정
- 1이동: 대시보드 → 웹훅 → 웹훅 추가
- 2입력: 엔드포인트 URL — HTTPS로 공개 접근 가능해야 함
- 3선택: 수신할 이벤트
- 4복사: 서명 시크릿 — 한 번만 표시되므로 안전하게 보관
- 5설정: 서버 환경에 AUTHON_WEBHOOK_SECRET 추가
이벤트 유형
| 이벤트 | 트리거 |
|---|---|
| user.created | 새 사용자가 등록을 완료함 |
| user.updated | 사용자 프로필이 업데이트됨 |
| user.deleted | 사용자 계정이 영구 삭제됨 |
| user.signin | 사용자가 로그인함 (이메일 또는 OAuth) |
| user.signout | 사용자가 로그아웃함 |
| user.banned | 관리자가 사용자를 차단함 |
| user.unbanned | 차단된 사용자가 복원됨 |
| session.created | 새 세션이 생성됨 (로그인, 토큰 갱신) |
| session.revoked | 세션이 취소됨 (로그아웃, 관리자 강제 취소) |
페이로드 형식
모든 웹훅 페이로드는 일관된 최상위 구조를 가진 JSON 객체입니다. data 필드에 이벤트별 세부 정보가 포함됩니다.
{
"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"
}session.*이벤트의 경우, data필드에 session객체(id, ipAddress, userAgent)도 포함됩니다.
서명 검증
각 웹훅 요청에는 X-Authon-Signature 형식의 v1=<hex_digest>. 헤더가 포함됩니다. 서명은 timestamp.rawBody 에 대해 웹훅 시크릿으로 HMAC-SHA256을 계산한 값입니다. 타이밍 안전 비교로 검증하세요.
| 헤더 | 형식 | 설명 |
|---|---|---|
| X-Authon-Signature | v1={hmac_sha256} | 요청 출처 검증을 위한 HMAC-SHA256 서명 |
| X-Authon-Timestamp | ISO 8601 | 이벤트 전송 시각 (ISO 8601) |
| X-Authon-Event | user.created | 이벤트 유형 (예: user.created, session.revoked) |
json() 미들웨어는 본문을 재직렬화하여 공백이 변경되고 서명이 깨질 수 있습니다.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;SDK 사용
@authon/node SDK는 타이밍 안전 비교를 처리하는 내장 검증 헬퍼를 제공합니다:
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 });
}
);재시도 정책
엔드포인트가 비-2xx 상태 코드를 반환하거나 10초내에 응답하지 않으면, Authon은 지수 백오프로 전송을 재시도합니다. 최대 3회 시도합니다.
| 시도 | 지연 | 누적 시간 |
|---|---|---|
| 최초 | — | 0s |
| 1차 재시도 | 1 second | ~1s |
| 2차 재시도 | 2 seconds | ~3s |