Усі статті
Події життєвого циклу користувачів Clerk проходять через підписаний webhook-тунель до endpoint Next.js App Router і локальної бази даних.
ClerkNext.jswebhooksuser sync

Як тестувати вебхуки Clerk на localhost у Next.js

Щоб перевірити вебхуки Clerk на локальному хості в Next.js, створіть POST-маршрут App Router, відкрийте порт 3000 за допомогою тунелю HTTPS, додайте загальнодоступну URL-адресу як кінцеву точку вебхуку Clerk і перевіряйте кожен запит за допомогою verifyWebhook() перед синхронізацією даних користувача. Зберігайте маршрут відкритим у проміжному програмному забезпеченні Clerk: секрет підпису автентифікує міжмашинний запит, а не сеанс браузера.

Коли вебхуки Clerk є правильним інструментом синхронізації

Clerk залишається джерелом істини. Вебхук корисний, коли вашій програмі потрібна локальна проекція для об’єднань, пошуку, звітування, метаданих авторизації або інтеграцій, які не можуть запитувати Clerk на вимогу. Типові події включають user.created, user.updated, і user.deleted.

Вебхук є асинхронним. Користувач може завершити реєстрацію до того, як ваша проекція бази даних буде створена, доставку можна спробувати повторно, а оновлення можуть надійти близько один до одного. Не робіть проекцію єдиним джерелом для перевірки особи відразу після реєстрації. Дизайн допускає коротку затримку або створює рядок програми явно в потоці користувача та дозволяє вебхукам узгоджувати його.

Створіть загальнодоступну кінцеву точку маршрутизатора програми Next.js

додати app/api/webhooks/clerk/route.ts. Clerkівський струм посібник із синхронізації використовує verifyWebhook від @clerk/nextjs/webhooks. Помічник використовує запит, перевіряє підпис Standard Webhooks і повертає введені дані події.

// app/api/webhooks/clerk/route.ts
import { verifyWebhook } from '@clerk/nextjs/webhooks';
import { NextRequest } from 'next/server';

export const runtime = 'nodejs';

export async function POST(request: NextRequest) {
  try {
    const event = await verifyWebhook(request);

    await processOnce(event, async () => {
      switch (event.type) {
        case 'user.created':
        case 'user.updated':
          await upsertClerkUser(event.data);
          break;
        case 'user.deleted':
          if (event.data.id) await archiveClerkUser(event.data.id);
          break;
      }
    });

    return new Response('accepted', { status: 200 });
  } catch (error) {
    console.error('Clerk webhook rejected', safeError(error));
    return new Response('invalid webhook', { status: 400 });
  }
}

За замовчуванням помічник читає CLERK_WEBHOOK_SIGNING_SECRET. Clerk verifyWebhook посилання також дозволяє явний signingSecret параметр, але конфігурація середовища уникає вбудовування секрету в джерело.

Виключити маршрут webhook із захисту сеансу

Запити Webhook не передають сеанс Clerk вашого користувача. Якщо виклики проміжного ПЗ auth.protect() для кожного шляху API доставка Clerk отримує перенаправлення 401 або 404 перед запуском перевірки підпису. Визначте захищені маршрути додатків явно та вийдіть /api/webhooks/clerk громадськість.

// middleware.ts for Next.js 15 and earlier
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';

const isProtectedRoute = createRouteMatcher([
  '/dashboard(.*)',
  '/api/private(.*)',
]);

export default clerkMiddleware(async (auth, request) => {
  if (isProtectedRoute(request)) await auth.protect();
});

export const config = {
  matcher: [
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico)).*)',
    '/(api|trpc)(.*)',
  ],
};

Clerk посібник із налагодження вебхука спеціально викликає виключення маршрутів вебхуку. У новіших версіях Next.js може використовуватися конвенція proxy.ts; дотримуйтеся посібника з версії Clerk, встановленого у вашому проекті. Громадський не означає довірений: verifyWebhook() є обов'язковим перед будь-якими діями.

Підключіть Clerk до localhost

  1. бігти npm run dev і переконайтеся, що програма Next.js прослуховує порт 3000.
  2. бігти npx portpreview 3000.
  3. На інформаційній панелі Clerk створіть кінцеву точку вебхуку за допомогою https://your-subdomain.portpreview.dev/api/webhooks/clerk.
  4. Виберіть лише потрібні події користувача, сеансу, організації чи електронної пошти.
  5. Скопіюйте секрет підпису кінцевої точки CLERK_WEBHOOK_SIGNING_SECRET у вашому локальному середовищі та перезапустіть Next.js.
  6. Відкрийте вкладку «Тестування» кінцевої точки, виберіть user.createdі виберіть Надіслати приклад.
  7. Переконайтеся, що спроба каже «Успішно», ваш локальний маршрут повернув 200, а очікуваний рядок бази даних змінився один раз.

URL-адреса тунелю має залишатися активною для подальших прикладів. Якщо зміниться, оновіть кінцеву точку. Не використовуйте повторно секрет підпису робочої кінцевої точки для локальних тестів; створювати кінцеві точки для певного середовища, щоб історія ротації та аудиту залишалася чіткою.

Ретельно моделюйте синхронізацію користувачів

Використовуйте ідентифікатор користувача Clerk як зовнішній ключ

Магазин user_... в унікальному clerk_user_id колонка. Upsert на цьому ключі, тому повторна спроба user.created зближується замість того, щоб виходити з ладу. Зберігайте власний внутрішній первинний ключ, якщо на нього вже посилаються інші таблиці.

Вибирайте основну електронну адресу свідомо

Дані користувача Clerk містять записи адрес електронної пошти та ідентифікатор основної адреси електронної пошти. Розділіть основний запис за ідентифікатором замість першого елемента масиву. Електронна пошта може змінюватися; не використовуйте його як незмінний зовнішній ключ.

Вирішіть, що означає видалення

А user.deleted Подія може містити менше даних, ніж створити або оновити. Використовуйте ідентифікатор для анонімізації, м’якого видалення або запуску робочого циклу збереження відповідно до вашої політики. Сліпе каскадне видалення може знищити записи про виставлення рахунків або аудит, збереження яких вимагають нормативні акти.

Не віддзеркалюйте все

Зберігайте лише ті поля, які потрібні вашій програмі. Кожне скопійоване поле профілю створює зобов’язання конфіденційності, збереження та застарілості. Отримайте рідко використовувані дані Clerk на вимогу, а не дублюйте всю корисну інформацію.

Зробіть повторні спроби та замовлення нешкідливими

Clerk документує, що відповідь, відмінна від 2xx, викликає повторну спробу події. Запишіть ідентифікатор повідомлення вебхуку з підписаних метаданих або заголовків вебхуку як унікальну квитанцію перед застосуванням ефектів. Якщо ваш SDK надає стандартні ідентифікатори вебхуків у заголовках, збережіть їх разом із типом події та міткою часу. Поверніть 200 для завершеного дубліката.

Для оновлень користувачів порівняйте позначки часу подій або використовуйте правила останнього запису, які запобігають перезапису старішою подією нових даних профілю. Для високого стану отримайте поточного користувача з Clerk після перевірки та розглядайте вебхук як сигнал для узгодження. Зберігайте вставку квитанції, оновлення користувача та завдання вихідної папки в одній транзакції бази даних.

await db.transaction(async (tx) => {
  const inserted = await tx.webhookReceipt.insertIfAbsent(messageId);
  if (!inserted) return;

  await tx.user.upsert({
    clerkUserId: clerk.id,
    primaryEmail: findPrimaryEmail(clerk),
    sourceUpdatedAt: eventTimestamp,
  });
  await tx.outbox.enqueue('profile-synced', { clerkUserId: clerk.id });
});

Цей шаблон запобігає дублюванню вітальних листів і частковим записам. див повторні спроби веб-хуку та ідемпотентність для параметрів схеми.

Вирішення проблем із доставкою місцевого Clerk

404, переспрямування або HTML замість вашого обробника

Перевірте шлях до файлу, експорт POST і повну URL-адресу тунелю. Перевірте перезапис проміжного програмного забезпечення та локалі. Вебхук не повинен проходити через переспрямування входу або перевірку форми CSRF. Перевірте загальнодоступну URL-адресу за допомогою простого POST; очікуйте відхилення підпису від вашого маршруту, а не фреймворку 404.

verifyWebhook() завжди кидає

Перезапустіть Next.js після встановлення секретного підпису. Підтвердьте, що секрет належить цій кінцевій точці та середовищу. Не аналізуйте, не клонуйте неправильно та не використовуйте тіло запиту, перш ніж передати його помічнику. Переконайтеся, що тунель зберігає стандартні заголовки підпису Webhooks.

Інформаційна панель показує повторні спроби

Подивіться на точну відповідь спроби. Повертайте 2xx лише після тривалого прийняття, але продовжуйте обробку нижче часу очікування постачальника. Переміщення бази даних, помилки унікальних обмежень і синхронний виклик недоступної служби є поширеними 500 причинами.

Рядки дублюються або застарілі

Додайте унікальні обмеження для ідентифікатора Clerk ID та ідентифікатора повідомлення webhook. зробити user.created і user.updated обидві безпечні upserts, а потім захистити від старіших позначок часу подій. Відтворюйте приклад після кожного виправлення, щоб підтвердити повторну обробку.

Контрольний список безпеки

  • Перевіряйте кожен запит за допомогою помічника Clerk, перш ніж реєструвати поля корисного навантаження або записувати дані.
  • Зберігайте маршрут без автентифікації проміжним програмним забезпеченням сеансу користувача, але захищеним підписом вебхука.
  • Використовуйте окремі секрети кінцевих точок для локального середовища, середовища попереднього перегляду, постановки та виробництва.
  • Дедуплікація підписаних ідентифікаторів повідомлень і однозначне обмеження ідентифікаторів користувачів.
  • Видаліть електронну пошту, телефон, маркери, секрети та повне корисне навантаження зі звичайних журналів.
  • Додатково додайте задокументовані IP-контролю Clerk/Svix як глибокий захист, але ніколи не замінюйте перевірку підпису фільтрацією IP.
  • Обмежте швидкість недійсного трафіку, обмежте розмір тіла та змініть секрет, якщо він з’являється в журналах або системі керування джерелами.

Clerk огляд веб-хуків пояснює перевірку підпису та додаткові обмеження IP-адреси Svix. Щодо основ необробленого тіла Next.js і поведінки маршруту продовжуйте з Посібник з вебхуку локального хосту Next.js.

Поширені запитання

Як локально протестувати webhook Clerk у Next.js?
Створіть POST-маршрут App Router, відкрийте порт 3000 через HTTPS-тунель, додайте повний публічний маршрут у Clerk Dashboard, задайте CLERK_WEBHOOK_SIGNING_SECRET і надішліть приклад із вкладки тестування endpoint.
Чи потрібно захищати маршрут webhook Clerk через clerkMiddleware?
Маршрут має бути доступним без користувацької сесії, тому не викликайте для нього auth.protect(). Автентифікуйте міжмашинний запит за допомогою verifyWebhook() і секрету підпису endpoint.
Чи потрібно розбирати raw body до Clerk verifyWebhook()?
Ні. Передайте початковий Request безпосередньо у verifyWebhook(). Не викликайте перед цим request.json() або request.text(), адже helper потрібні підписане тіло запиту й заголовки.
Як обробляти повторні доставки Clerk user.created?
Виконуйте upsert за унікальним ID користувача Clerk, усувайте дублікати за ID підписаного webhook-повідомлення та повертайте 200 для вже обробленої події. Необов’язкові побічні ефекти ставте в чергу, щоб не дублювати листи.