clerk-webhooks は何をしますか?
ClerkのWebhookを使用して、リアルタイムイベントとデータ同期を実現します。各フレームワーク固有のパッケージからverifyWebhookを使って検証し、ユーザー、セッション、組織、請求、支払いイベントを処理します。データベース同期、通知、統合などのイベント駆動機能を構築できます。
概要
Clerk Webhookは、アプリケーション内の認証およびユーザー管理イベントをリアルタイムで外部システムに通知するためのメカニズムです。ユーザー作成、セッション開始、組織変更などのイベントが発生すると、Clerkは設定されたエンドポイントにHTTP POSTリクエストを送信します。
セットアップ
- Clerkダッシュボードの「Webhooks」セクションでエンドポイントを追加します。
- 受信するイベントタイプ(例:
user.created、session.ended、organization.updated)を選択します。 - エンドポイントのシークレットキーを環境変数(例:
CLERK_WEBHOOK_SECRET)に保存します。
検証
各フレームワーク固有のClerk SDKにはverifyWebhook関数が含まれており、Webhookリクエストの署名を検証します。
Node.js(Express)の例
import { Webhook } from 'svix';
const webhookSecret = process.env.CLERK_WEBHOOK_SECRET;
app.post('/api/webhooks', async (req, res) => {
const payload = req.body;
const headers = req.headers;
const wh = new Webhook(webhookSecret);
let event;
try {
event = wh.verify(payload, headers);
} catch (err) {
return res.status(400).json({ error: 'Webhook verification failed' });
}
const eventType = event.type;
const eventData = event.data;
// イベントの処理
switch (eventType) {
case 'user.created':
// 新しいユーザーをデータベースに同期
break;
case 'session.ended':
// セッション終了時の処理
break;
default:
// 未処理のイベントタイプ
}
res.status(200).end();
});
Next.js App Routerの例
import { Webhook } from 'svix';
import { headers } from 'next/headers';
import { WebhookEvent } from '@clerk/nextjs/server';
export async function POST(req: Request) {
const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET;
if (!WEBHOOK_SECRET) {
throw new Error('Please add CLERK_WEBHOOK_SECRET to .env.local');
}
const headerPayload = headers();
const svixId = headerPayload.get('svix-id');
const svixTimestamp = headerPayload.get('svix-timestamp');
const svixSignature = headerPayload.get('svix-signature');
if (!svixId || !svixTimestamp || !svixSignature) {
return new Response('Error: Missing Svix headers', { status: 400 });
}
const payload = await req.json();
const body = JSON.stringify(payload);
const wh = new Webhook(WEBHOOK_SECRET);
let evt: WebhookEvent;
try {
evt = wh.verify(body, {
'svix-id': svixId,
'svix-timestamp': svixTimestamp,
'svix-signature': svixSignature,
}) as WebhookEvent;
} catch (err) {
return new Response('Error: Verification failed', { status: 400 });
}
// イベントの処理
const { id } = evt.data;
const eventType = evt.type;
switch (eventType) {
case 'user.created':
console.log('User created:', id);
break;
case 'user.updated':
console.log('User updated:', id);
break;
case 'user.deleted':
console.log('User deleted:', id);
break;
default:
console.log('Unhandled event type:', eventType);
}
return new Response('Webhook received', { status: 200 });
}
イベントタイプ
ユーザーイベント
user.created- 新しいユーザーが作成されたuser.updated- ユーザー情報が更新されたuser.deleted- ユーザーが削除された
セッションイベント
session.created- 新しいセッションが開始されたsession.ended- セッションが終了したsession.revoked- セッションが取り消された
組織イベント
organization.created- 新しい組織が作成されたorganization.updated- 組織情報が更新されたorganization.deleted- 組織が削除されたorganizationMembership.created- メンバーが追加されたorganizationMembership.deleted- メンバーが削除された
課金/支払いイベント(Clerkの課金アドオン使用時)
billing.created- 課金レコードが作成されたbilling.updated- 課金情報が更新されたpayment.successful- 支払いが成功したpayment.failed- 支払いが失敗した
ユースケース
データベース同期
新しいユーザーが登録した際に、user.createdイベントを処理してユーザープロファイルをデータベースに自動同期します。
通知送信
セッション開始や組織変更イベントをトリガーに、メールやSlack通知を送信します。
外部統合
ユーザー削除イベントをキャッチして、CRMやメーリングリストなど外部サービスからもユーザーを削除します。
ベストプラクティス
- 常にWebhookリクエストの署名を検証して、正当性を確認してください。
- 重複配信を考慮して、べき等性を確保する処理を実装してください。
- イベント処理に失敗した場合のリトライ戦略を用意してください。
- 環境変数を使ってシークレットキーを管理し、コードに直接記述しないでください。