Aby przetestować webhooki Clerk na hoście lokalnym w Next.js, utwórz trasę POST App Router, udostępnij port 3000 za pomocą tunelu HTTPS, dodaj publiczny adres URL jako punkt końcowy webhooka Clerk i zweryfikuj każde żądanie za pomocą verifyWebhook() przed synchronizacją danych użytkownika. Zachowaj trasę publiczną w oprogramowaniu pośrednim Clerk: klucz podpisywania uwierzytelnia żądanie maszyna-maszyna, a nie sesję przeglądarki.
Kiedy webhooki Clerk są właściwym narzędziem do synchronizacji
Clerk pozostaje tożsamościowym źródłem prawdy. Element webhook jest przydatny, gdy aplikacja wymaga lokalnej projekcji na potrzeby połączeń, wyszukiwania, raportowania, metadanych autoryzacji lub integracji, które nie mogą wysyłać zapytań do Clerk na żądanie. Typowe wydarzenia obejmują user.created, user.updated, I user.deleted.
Element webhook jest asynchroniczny. Użytkownik może zakończyć rejestrację przed utworzeniem projekcji bazy danych, można ponowić dostawę, a aktualizacje mogą dotrzeć blisko siebie. Nie traktuj projekcji jako jedynego źródła bezpośredniej kontroli tożsamości po rejestracji. Zaprojektuj odczyty tak, aby tolerowały krótkie opóźnienie lub utwórz wiersz aplikacji jawnie w przepływie użytkownika i pozwól, aby webhooki to pogodziły.
Utwórz publiczny punkt końcowy routera aplikacji Next.js
Dodać app/api/webhooks/clerk/route.ts. Prąd Clerka przewodnik synchronizacji wykorzystuje verifyWebhook z @clerk/nextjs/webhooks. Pomocnik wykorzystuje żądanie, sprawdza podpis standardowych elementów webhook i zwraca wpisane dane zdarzenia.
// 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 });
}
}
Domyślnie pomocnik czyta CLERK_WEBHOOK_SIGNING_SECRET. Clerka zweryfikuj odwołanie do webhooka pozwala również na wyraźne signingSecret opcję, ale konfiguracja środowiska pozwala uniknąć osadzania klucza tajnego w źródle.
Wyklucz trasę webhooka z ochrony sesji
Żądania webhooka nie przenoszą sesji Clerk użytkownika. Jeśli oprogramowanie pośredniczące wywołuje auth.protect() dla każdej ścieżki API dostawa Clerka otrzymuje przekierowanie 401 lub 404 przed uruchomieniem weryfikacji podpisu. Zdefiniuj jawnie chronione trasy aplikacji i wyjdź /api/webhooks/clerk publiczny.
// 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)(.*)',
],
};
Clerka przewodnik debugowania webhooka wyraźnie wzywa do wykluczania tras webhook. W nowszych wersjach Next.js może być używana konwencja proxy.ts; postępuj zgodnie z przewodnikiem po wersji Clerk zainstalowanym w Twoim projekcie. Publiczne nie znaczy zaufane: verifyWebhook() jest obowiązkowe przed podjęciem jakichkolwiek działań.
Połącz Clerka z localhost
- Uruchomić
npm run devi sprawdź, czy aplikacja Next.js nasłuchuje na porcie 3000. - Uruchomić
npx portpreview 3000. - W panelu Clerka utwórz punkt końcowy elementu webhook za pomocą
https://your-subdomain.portpreview.dev/api/webhooks/clerk. - Wybierz tylko wymagane zdarzenia dotyczące użytkownika, sesji, organizacji lub poczty e-mail.
- Skopiuj sekret podpisywania punktu końcowego do
CLERK_WEBHOOK_SIGNING_SECRETw swoim środowisku lokalnym i uruchom ponownie Next.js. - Otwórz kartę Testowanie punktu końcowego i wybierz
user.createdi wybierz opcję Wyślij przykład. - Potwierdź, że próba zakończyła się sukcesem, trasa lokalna zwróciła 200, a oczekiwany wiersz bazy danych zmienił się raz.
Adres URL tunelu musi pozostać aktywny dla kolejnych przykładów. Jeśli się zmieni, zaktualizuj punkt końcowy. Nie używaj ponownie sekretu podpisywania produkcyjnego punktu końcowego do testów lokalnych; twórz punkty końcowe specyficzne dla środowiska, aby rotacja i historia audytów pozostały jasne.
Starannie modeluj synchronizację użytkowników
Użyj identyfikatora użytkownika Clerk jako klucza zewnętrznego
Sklep user_... w wyjątkowym clerk_user_id kolumna. Wstaw ten klucz, aby spróbować ponownie user.created zbiega się, zamiast zawodzić. Zachowaj własny wewnętrzny klucz podstawowy, jeśli inne tabele już się do niego odwołują.
Wybierz celowo główny adres e-mail
Dane użytkownika Clerk obejmują rekordy adresów e-mail i identyfikator podstawowego adresu e-mail. Rozwiąż podstawowy rekord według identyfikatora zamiast przyjmować pierwszy element tablicy. Adres e-mail może ulec zmianie; nie używaj go jako niezmiennego klucza obcego.
Zdecyduj, co oznacza usunięcie
A user.deleted zdarzenie może zawierać mniej danych niż utworzenie lub aktualizacja. Użyj identyfikatora, aby anonimizować, usuwać nietrwale lub rozpoczynać proces przechowywania zgodnie ze swoimi zasadami. Ślepe usuwanie kaskadowe może zniszczyć zapisy rozliczeniowe lub audytowe, których zachowanie wymagają przepisy.
Nie odzwierciedlaj wszystkiego
Utrzymuj tylko pola wymagane przez aplikację. Każde skopiowane pole profilu stwarza obowiązek dotyczący prywatności, przechowywania i nieaktualności. Pobieraj rzadko używane dane Clerk na żądanie, zamiast duplikować cały ładunek.
Spraw, aby ponowne próby i składanie zamówień były nieszkodliwe
Clerk dokumentuje, że odpowiedź inna niż 2xx powoduje ponowną próbę zdarzenia. Zapisz identyfikator wiadomości webhooka z podpisanych metadanych lub nagłówków webhooka jako unikalne potwierdzenie przed zastosowaniem efektów. Jeśli Twój pakiet SDK udostępnia w nagłówkach standardowe identyfikatory webhooków, zachowaj je wraz z typem zdarzenia i sygnaturą czasową. Zwróć 200 za ukończony duplikat.
W przypadku aktualizacji użytkowników porównaj sygnatury czasowe zdarzeń lub użyj reguł ostatniego zapisu, które zapobiegają zastąpieniu nowszych danych profilu przez starsze wydarzenie. W przypadku stanu o dużej wartości pobierz bieżącego użytkownika od Clerk po weryfikacji i potraktuj webhooka jako sygnał do uzgodnienia. Zachowaj wkładkę paragonu, aktualizację użytkownika i zadanie skrzynki nadawczej w jednej transakcji bazy danych.
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 });
});
Ten wzorzec zapobiega duplikowaniu wiadomości powitalnych i częściowym zapisom. Widzieć ponowne próby webhooka i idempotencja dla opcji schematu.
Rozwiązywanie problemów z dostawami lokalnymi Clerkami
404, przekierowanie lub HTML zamiast modułu obsługi
Sprawdź ścieżkę pliku, eksport POST i adres URL pełnego tunelu. Sprawdź przepisanie oprogramowania pośredniego i ustawień regionalnych. Webhook nie powinien przechodzić przez przekierowanie logowania ani kontrolę formularza CSRF. Przetestuj publiczny adres URL za pomocą podstawowego testu POST; spodziewaj się odrzucenia podpisu na swojej trasie, a nie na platformie 404.
verifyWebhook() zawsze rzuca
Uruchom ponownie Next.js po ustawieniu sekretu podpisywania. Potwierdź, że klucz tajny należy do tego punktu końcowego i środowiska. Nie analizuj, nie klonuj niepoprawnie ani nie zużywaj treści żądania przed przekazaniem jej pomocnikowi. Upewnij się, że tunel zachowuje nagłówki podpisu standardowych elementów Webhooks.
Na pulpicie nawigacyjnym wyświetlane są ponowne próby
Spójrz na dokładną reakcję na próbę. Zwróć wartość 2xx dopiero po trwałej akceptacji, ale kontynuuj przetwarzanie poniżej limitu czasu dostawcy. Migracje baz danych, błędy związane z ograniczeniami unikalności i synchroniczne wywoływanie niedostępnej usługi to 500 częstych przyczyn.
Wiersze są zduplikowane lub nieaktualne
Dodaj unikalne ograniczenia dla identyfikatora Clerka i identyfikatora wiadomości webhooka. Robić user.created I user.updated oba bezpieczne wstawki, a następnie chroń się przed starszymi znacznikami czasu zdarzeń. Powtórz przykład po każdej poprawce, aby udowodnić zduplikowaną obsługę.
Lista kontrolna bezpieczeństwa
- Przed zalogowaniem pól ładunku lub zapisaniem danych zweryfikuj każde żądanie za pomocą pomocnika Clerka.
- Zachowaj trasę nieuwierzytelnioną przez oprogramowanie pośredniczące sesji użytkownika, ale zabezpieczoną sygnaturą elementu webhook.
- Użyj oddzielnych kluczy tajnych punktów końcowych dla środowisk lokalnych, podglądowych, przejściowych i produkcyjnych.
- Deduplikuj identyfikatory podpisanych wiadomości i ograniczaj unikalne identyfikatory użytkowników.
- Redaguj wiadomości e-mail, telefony, tokeny, sekrety i pełne ładunki ze zwykłych dzienników.
- Opcjonalnie dodaj udokumentowaną kontrolę IP Clerk/Svix jako głęboką ochronę, ale nigdy nie zastępuj weryfikacji podpisu filtrowaniem IP.
- Ogranicz nieprawidłowy ruch, ogranicz rozmiar treści i obróć klucz tajny, jeśli pojawi się w dziennikach lub kontroli źródła.
Clerka przegląd webhooków wyjaśnia weryfikację podpisu i opcjonalne ograniczenia IP Svix. Aby zapoznać się z podstawami surowej treści i zachowaniem tras w Next.js, przejdź do Przewodnik po webhooku Next.js localhost.
