LoginSignup
nekokota
@nekokota

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Clerkのwebhookがfailedになってしまう

解決したいこと

Clerkのwebhookでユーザー情報を同期したいです。clerkのdashbordでwebhookのテストしてみるとsuccessが返り、テスト情報がDBに保存されます。Vercelやngrokでデプロイした環境でテストではなく普通に認証を行うと、DBに保存されません。

該当のソースコード

import { WebhookEvent } from '@clerk/nextjs/server';
import { headers } from 'next/headers';
import { NextResponse } from 'next/server';
import { db } from '../../../server/db/index';
import { q } from '../../../server/db/schema';

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 from Clerk Dashboard to .env or .env.local');
  }

  const headerPayload = headers();
  const svix_id = headerPayload.get("svix-id");
  const svix_timestamp = headerPayload.get("svix-timestamp");
  const svix_signature = headerPayload.get("svix-signature");

  console.log('Headers:', { svix_id, svix_timestamp, svix_signature });

  if (!svix_id || !svix_timestamp || !svix_signature) {
    return NextResponse.json({ message: 'Error occured - missing 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": svix_id,
      "svix-timestamp": svix_timestamp,
      "svix-signature": svix_signature,
    }) as WebhookEvent;
    console.log('Verified Event:', evt);
  } catch (err) {
    console.error('Error verifying webhook:', err);
    return NextResponse.json({ message: 'Error occured' }, { status: 400 });
  }

  if (evt.type === 'user.created' || evt.type === 'user.updated') {
    const { id, email_addresses } = evt.data;
    const primaryEmail = email_addresses.find(email => email.id === evt.data.primary_email_address_id);

    if (primaryEmail) {
      console.log('Inserting or updating user:', { id, email: primaryEmail.email_address });
      try {
        await db.insert(q).values({
          id: id,
          email: primaryEmail.email_address,
        }).onConflictDoUpdate({
          target: q.id,
          set: { email: primaryEmail.email_address, updatedAt: new Date() },
        });
      } catch (error) {
        console.error('Database insertion error:', error);
      }
    }}
  return NextResponse.json({ message: 'Received' }, { status: 200 });
}

dashbordからテストした結果 updateされ、DBにも保存されました
スクリーンショット 2024-07-22 235315.png

デプロイした環境で認証 createされませんでした
スクリーンショット 2024-07-22 235044.png

どこを直せばいいのか全く分からないです。どうすればいいのでしょうか

0

2Answer

wh.verify() が成功しているということは、保存処理まで到達するどうかは evt の中身だけによって決まりますよね(到達する条件は evt.type === 'user.created' || evt.type === 'user.updated' が真であり、かつ primaryEmail が取得できていることです)。Inserting or updating user: メッセージすら出ないなら evt がそこまで行く条件を満たしていないということなので、何がおかしいか console.log('Verified Event:', evt) の出力を確認してください。

1Like

Comments

  1. @nekokota

    Questioner

    回答ありがとうございます!
    自己解決しました!

原因はわかりませんがdashbordのUsersを消して再度やってみたところ無事保存されました

0Like

Your answer might help someone💌