Zum Hauptinhalt springen
Dieser Leitfaden behandelt die häufigsten Probleme, die bei der Integration von Ribaunt auftreten können, und wie du sie löst. Für jedes Problem findest du die wahrscheinliche Ursache und die genaue Lösung.
Ursache: RIBAUNT_SECRET fehlt in deiner Umgebung oder wurde nicht in den Prozess geladen, bevor createChallenge oder verifySolution zum ersten Mal aufgerufen wurde.Lösung: Stelle sicher, dass die Variable definiert ist, bevor dein Server seine erste Anfrage bearbeitet. Wenn du eine .env-Datei verwendest, lade sie ganz oben in deinem Einstiegspunkt mit einem Tool wie dotenv:
import 'dotenv/config'; // Must come before any ribaunt imports
import { createChallenge } from 'ribaunt';
Für gehostete Laufzeitumgebungen (Vercel, Railway, Fly.io usw.) solltest du RIBAUNT_SECRET über das Umgebungsvariablen-Dashboard deiner Plattform setzen, anstatt es in die Versionskontrolle einzuchecken. Rotiere das Secret sofort, falls es jemals versehentlich offengelegt wird.
Ursache: Der Browser-Solver erfordert einen sicheren Kontext. Reines HTTP auf einem beliebigen Host außer localhost qualifiziert sich nicht. Das betrifft häufig Geräte in einem lokalen Netzwerk, auf die über eine IP-Adresse wie http://192.168.x.x zugegriffen wird.Lösung:
  • Produktion: Stelle deine App immer über HTTPS bereit.
  • Entwicklung: Verwende http://localhost statt der LAN-IP deines Rechners. Wenn andere Geräte im Netzwerk auf deinen Dev-Server zugreifen müssen, terminiere TLS mit einem Tool wie mkcert oder einem lokalen Reverse Proxy.
Ursache: Die TTL des Challenge-Tokens ist abgelaufen, bevor der Browser seine Lösung eingereicht hat. Das kann auf Seiten passieren, die lange zum Laden brauchen, in Formularen, in denen Benutzer mehrere Minuten verbringen, oder wenn Server- und Client-Uhren erheblich abweichen.Lösung: Erhöhe ttlSeconds in deinem createChallenge-Aufruf, um den Benutzern mehr Zeit zu geben. Der Standard ist 30 Sekunden; erwäge 120–300 für komplexe Seiten oder Formulare:
// Allow up to 5 minutes to complete the form
const tokens = createChallenge(5, 4, 300);
Ursache: Dieselben Challenge-Tokens wurden mehr als einmal eingereicht. Das ist beabsichtigt — Ribaunts Standard-local-Replay-Store markiert Tokens beim ersten Gebrauch als verbraucht und lehnt jede weitere Einreichung ab.Lösung: Wenn dies in normalen Benutzerabläufen geschieht, sendet dein Frontend höchstwahrscheinlich dieselben Tokens erneut (z. B. bei einem Formular-Retry). Stelle für jeden Versuch frische Tokens aus, indem du deinen Challenge-Endpunkt vor dem erneuten Absenden noch einmal aufrufst.Wenn du dies in Serverless- oder Multi-Instance-Deployments siehst, liegt das Problem darin, dass jeder Funktionsaufruf seinen eigenen In-Memory-Store hat. Tokens, die in einer Instanz verbraucht wurden, sind für andere unsichtbar. Wechsle zu replayPrevention: 'remote' mit einem verteilten Store:
const isValid = await verifySolution(tokens, solutions, {
  replayPrevention: 'remote',
  replayStore: {
    consume: async (jti, expiresAt) => {
      // Use Redis/Valkey SET NX EX for atomic consume semantics
      const result = await redisClient.set(jti, '1', { NX: true, EXAT: expiresAt });
      return result === 'OK';
    },
  },
});
Ursache: Das Attribut auto-verify fehlt, oder das Widget ist im Zustand disabled, was verhindert, dass auto-verify ausgelöst wird, selbst wenn es gesetzt ist.Lösung: Füge dem HTML-Element auto-verify="true" hinzu oder im React-Wrapper autoVerify={true}:
<ribaunt-widget
  challenge-endpoint="/api/challenge"
  verify-endpoint="/api/verify"
  auto-verify="true"
></ribaunt-widget>
Prüfe außerdem, dass disabled entweder nicht vorhanden oder explizit auf "false" gesetzt ist. Solange das Widget deaktiviert ist, wird auto-verify nicht ausgelöst.
Ursache: Das Widget-Skript wird nicht korrekt geladen. Häufige Ursachen sind ein falscher Pfad zur gebauten Datei, das Laden des Skripts ohne type="module" oder ein Bundler, der den Browser-Export des Pakets nicht korrekt auflöst.Lösung: Lade das Widget-Skript als Modul und stelle sicher, dass der Pfad auf dist/widget-browser.js zeigt:
<script type="module" src="/node_modules/ribaunt/dist/widget-browser.js"></script>
Wenn du das Widget selbst bündelst, stelle sicher, dass dein Bundler die browser-Export-Bedingung aus dem Ribaunt-Paket auflöst. Sieh in der Dokumentation deines Frameworks nach, wie Export-Bedingungen konfiguriert werden, falls das Widget weg-tree-shaken wird oder nicht gefunden wird.
Ursache: Der Standard-local-Replay-Store lebt im Prozessspeicher. In Serverless-Umgebungen ist jeder Funktionsaufruf ein frischer Prozess, sodass Tokens, die in einem vorherigen Aufruf verbraucht wurden, für den nächsten unbekannt sind. Das führt dazu, dass der In-Memory-Store jede Einreichung als die erste behandelt — aber wenn zwei gleichzeitige Aufrufe rennen, könnten beide dasselbe Token konsumieren, oder keiner hält den Zustand lange genug, um vor Replays zu schützen.Lösung: Wechsle zu replayPrevention: 'remote' mit einem Redis- oder Valkey-Adapter, der atomare SET NX EX-Semantik verwendet:
const isValid = await verifySolution(tokens, solutions, {
  replayPrevention: 'remote',
  replayStore: {
    consume: async (jti, expiresAt) => {
      const result = await redis.set(`ribaunt:${jti}`, '1', {
        NX: true,
        EXAT: expiresAt,
      });
      return result === 'OK';
    },
  },
});
Ursache: Die <ribaunt-widget>-Web-Komponente registriert sich mit ausschließlich browserseitigen APIs wie customElements und window. Diese sind während des serverseitigen Renderings nicht verfügbar.Lösung: Füge 'use client' am Anfang jeder Komponentendatei hinzu, die RibauntWidget importiert oder rendert:
'use client';

import { RibauntWidget } from 'ribaunt/widget-react';
Umschließe die Komponente nicht mit next/dynamic — der React-Wrapper von Ribaunt übernimmt das dynamische Importieren des Browser-Bundles bereits intern. Eine zweite Schicht dynamischen Imports kann diesen Mechanismus stören und doppeltes Laden oder Hydration-Mismatches verursachen.

Debug-Logging aktivieren

Standardmäßig protokolliert Ribaunt Verifizierungs-Warnungen in der Konsole, wenn NODE_ENV auf development gesetzt ist. In anderen Umgebungen sind Warnungen stumm, sofern du dich nicht aktiv dafür entscheidest. Verwende die Option debug, um die Konsolenausgabe explizit zu aktivieren, oder verwende onWarning für strukturiertes Logging, das in jeder Umgebung funktioniert.
const valid = await verifySolution(tokens, solutions, {
  debug: true, // Logs warnings to console in development
  onWarning: (w) => console.log(w.reason, w.message),
});
In NODE_ENV=development ist debug standardmäßig aktiviert — du musst es während der lokalen Entwicklung nicht explizit übergeben. Setze in der Produktion auf onWarning statt debug: true, um Anwendungsprotokolle nicht mit gering-aussagekräftigem Rauschen zu fluten.
Verwende in der Produktion den onWarning-Callback, um strukturierte Warngründe (invalid-token, expired-token, replay-detected usw.) für das Monitoring zu erfassen, ohne Logs zu fluten. Leite Warn-Ereignisse an deine Observability-Plattform (Datadog, Sentry usw.) weiter, um Einblick in ungewöhnliche Muster zu erhalten, ohne ausführliche Konsolenausgaben zu aktivieren.