Zum Inhalt springen

Sicherheitsgrundlagen

Warum Supabase-E-Mail-Links auf localhost:3000 weiterleiten

Leitet Supabase auf localhost:3000 um, ist die Site URL unverändert, oder deine Adresse fehlt in Redirect URLs. Die Lösung und der Platzhalter, den du meidest.

Vlad Tkachenko10 Min. Lesezeit
Ein Wegweiser, dessen leuchtender Arm von dem Haus weg zeigt, zu dem er führen soll, hin zu einem Laptop mit dunklem Bildschirm.

Kurz gesagt

  • Eine Weiterleitung von Supabase auf localhost:3000 kommt von der Site URL auf der Seite URL Configuration. Ein Projekt beginnt mit http://localhost:3000, und jeder E-Mail-Link fällt darauf zurück, wenn die Adresse, die deine App verlangt, nicht auf der Liste Redirect URLs steht.
  • Wer einen Registrierungslink gedrückt hat, ist meist schon bestätigt. Supabase bestätigt das Konto, bevor es die Person weiterschickt, also kann sie sich auf deiner echten Seite anmelden.
  • Setz die Site URL auf deine Live-Adresse und trag die genauen Adressen ein, die du benutzt. Ein Platzhalter, der so weit reicht, dass er die App eines anderen trifft, lässt einen präparierten Link deine Nutzer angemeldet dorthin schicken.

Ein neuer Nutzer registriert sich in deiner Live-App, öffnet die Bestätigungs-E-Mail und drückt auf den Knopf. Sein Browser öffnet eine Seite mit "This site can't be reached" und "localhost refused to connect" (so in einem englischen Chrome), über einer Adresse, die so beginnt:

http://localhost:3000/#access_token=…&expires_at=…&expires_in=…&refresh_token=…&sb=&token_type=bearer&type=signup

Nutzt deine App den PKCE-Ablauf, endet sie stattdessen auf ?code=…. Du hast die App mit Lovable, Bolt, v0, Cursor, Claude Code oder Replit gebaut, in der Vorschau lief sie tadellos, und die Anmeldung mit Passwort funktioniert immer noch.

Eine Weiterleitung von Supabase auf localhost heißt: Supabase Auth, der Teil von Supabase, der Leute anmeldet, hat seine Arbeit erledigt und die Person dann zur Site URL deines Projekts geschickt, und die steht noch auf http://localhost:3000. Diese Adresse bedeutet "dieser Computer". Auf dem Computer deines Nutzers ist dort nichts. Die Lösung sind zwei Einstellungen auf einer Seite deines Supabase-Dashboards.

Hier liegt der Teil, den die schnellen Lösungen im Netz falsch machen: Der Platzhalter, der diese Meldung mit einer Zeile verschwinden lässt, ist auch der, mit dem der Link eines Fremden deine Nutzer schon angemeldet auf seine Seite schickt. Die Einstellungen unten bringen die Links zum Laufen und halten diese Tür zu.

Was bedeutet eine Weiterleitung von Supabase auf localhost?

Sie bedeutet, dass Supabase die Person zur Standardadresse deines Projekts geschickt hat, weil es keine bessere angenommen hat.

Jede E-Mail, die Supabase für dich verschickt, ob Bestätigung der Registrierung, Magic Link, Zurücksetzen des Passworts oder Einladung, verlinkt zuerst auf die eigene Adresse deines Projekts. Supabases Anleitung zu den E-Mail-Vorlagen zeigt die Form: https://project-ref.supabase.co/auth/v1/verify?token=…&type=email&redirect_to=https://example.com/path. Dort prüft Supabase das Token und schickt den Browser dann weiter zu dem, was redirect_to nennt.

Stell es dir als Wegweiser an Supabases Tür vor. Jede Person, die einen Link öffnet, wird an der Tür angemeldet und dann, den Schlüssel in der Hand, einen der Arme entlang weitergeschickt. Die Arme stellst du auf. Die Site URL ist der Arm, den alle nehmen, wenn kein anderer passt, und bei einem neuen Projekt zeigt er auf http://localhost:3000: die Werkstatt, in der die App gebaut wurde, auf jedem anderen Rechner ein leerer Raum.

Supabases Anleitung zu Weiterleitungen sagt, dass die Site URL die Standard-Weiterleitung festlegt, wenn im Code kein redirectTo angegeben ist. Sie fordert dich auf, sie von http://localhost:3000 auf deine Produktionsadresse zu ändern, und nennt die Einstellung entscheidend für E-Mail-Bestätigungen und das Zurücksetzen von Passwörtern.

Warum übergeht Supabase die Adresse, die meine App verlangt hat?

Weil diese Adresse nicht auf deiner Liste Redirect URLs steht, und Supabase fällt zurück, ohne es dir zu sagen.

Deine App kann angeben, wo Leute landen sollen. In Supabases JavaScript-Bibliothek ist das emailRedirectTo bei signUp und signInWithOtp und redirectTo bei resetPasswordForEmail und signInWithOAuth. Supabase Auth entscheidet dann in einer kurzen Funktion, in dieser Reihenfolge:

  1. Die Adresse, die deine App verlangt hat, wenn sie zu einem Eintrag auf deiner Liste Redirect URLs passt oder auf derselben Domain wie deine Site URL liegt.
  2. Die Adresse der Seite, von der die Anfrage kam, so wie der Browser sie gemeldet hat, nach derselben Regel.
  3. Sonst die Site URL. Supabase meldet keinen Fehler, und die Konsole deiner App zeigt nichts.

Diese Entscheidung fällt, wenn die E-Mail verschickt wird, und die gewählte Adresse kommt in den Link. Öffnet jemand den Link, prüft Supabase diese Adresse noch einmal gegen deine Einstellungen, so wie sie in diesem Moment sind. Supabases eigene Antwort in der Fehlersuche fasst die Regel in einem Satz: Damit die übergebene Option redirectTo funktioniert, muss genau diese URL in der Einstellung Redirect URLs stehen.

Supabase versucht die Adresse, die deine App verlangt hat, dann die Seite, von der die Anfrage kam. Steht keine davon auf deiner Liste, entscheidet die Site URL.

Dieselbe Einstellung entscheidet, wohin "Sign in with Google" die Leute zurückschickt, ein Google-Knopf, der auf localhost landet, hat also dieselbe Ursache. Bleibt ein Google-Knopf schon früher stehen, auf einer Seite mit "Unsupported provider: provider is not enabled", geht es dagegen um einen Schalter in Supabase und eine Liste bei Google.

Warum du es vor dem Start nicht gesehen hast

Weil die beiden Wege, auf denen du getestet hast, die Site URL nie erreichen.

  • Die Anmeldung mit Passwort meldet Leute innerhalb der Seite an. Kein E-Mail-Link und kein Weg durch Supabases Tür, also wird der Wegweiser nie gelesen.
  • Wenn du mit Cursor oder Claude Code baust und dein Entwicklungsserver auf Port 3000 lief, als du die E-Mail getestet hast, hat der Link deine eigene lokale Kopie geöffnet und sah aus, als hätte er funktioniert.
  • Im eingebauten Backend von Lovable triffst du vielleicht nie darauf. Lovables Dokumentation zur Anmeldung sagt, dass es die Site URL beim Veröffentlichen auf deine Adresse unter lovable.app setzt und eine eigene Domain zu den Redirect URLs hinzufügt, wenn du sie verbindest. Dieselbe Seite sagt, dass Apps mit deinem eigenen Supabase-Projekt keine automatischen Aktualisierungen bekommen.

Ist das Konto bestätigt, obwohl die Seite nicht geladen hat?

Ja, bei einer Bestätigung der Registrierung. Supabase bestätigt zuerst und schickt den Browser erst danach weiter.

In dem Code, der den Link verarbeitet, wird das Konto bestätigt, bevor die Weiterleitung hinausgeht. Die Seite, die nicht lädt, kommt, wenn die Arbeit schon erledigt ist. Sag der Person also, dass sie sich auf deiner Live-Seite mit dem Passwort anmelden kann, das sie gewählt hat. Dieselbe E-Mail noch einmal zu drücken hilft nicht: Der Link funktioniert einmal, und der zweite Druck antwortet mit "Email link is invalid or has expired".

Ein Magic Link oder ein Zurücksetzen des Passworts ist etwas anderes. Diese Anmeldung ging nach localhost und blieb dort, also braucht die Person eine neue E-Mail, sobald du die Einstellungen korrigiert hast.

So behebst du die Weiterleitung von Supabase auf localhost

Ändere die Site URL und trag dann die anderen Adressen ein, zu denen du Leute schickst. Beides steht auf der Seite URL Configuration unter Authentication in deinem Supabase-Dashboard.

Setz die Site URL auf deine Live-Adresse, mit https:// davor.https://yourapp.com, vollständig geschrieben. Fehlt das https://, liest Supabase sie als Pfad auf seiner eigenen Adresse, und die Person landet stattdessen bei deinem Supabase-Projekt mit "No API key found in request". Jede Adresse auf dieser Domain wird danach unter jedem Pfad ohne Listeneintrag angenommen, https://yourapp.com/welcome funktioniert also, sobald die Site URL stimmt.

Trag die anderen Adressen in Redirect URLs ein. Die Version mit www, wenn Leute sie benutzen, die veröffentlichte Adresse beim Builder (https://yourapp.lovable.app zum Beispiel), wenn Leute sich dort registrieren, und sonst nichts. Ein Eintrag ist ein Muster, also deckt https://yourapp.com/** jede Seite auf dieser einen Domain ab.

Prüf, was dein Code verlangt. Übergibt er window.location.origin, ist die Adresse die, unter der die Seite geöffnet wurde, und jede Adresse, die dabei herauskommen kann, muss auf der Domain deiner Site URL oder auf der Liste liegen. Vergleich sie Zeichen für Zeichen: mit www oder ohne, mit https oder ohne. Ein Eintrag ohne /** am Ende passt auf genau diese Adresse und auf nichts darunter.

Prüf deine E-Mail-Vorlagen. Eine Vorlage, die ihren Link selbst aus {{ .SiteURL }} baut, schickt alle zur Site URL, egal was deine App verlangt hat. Supabases Anleitung zu Weiterleitungen sagt, dass du bei Verwendung der Option redirectTo in deinen E-Mail-Vorlagen womöglich {{ .SiteURL }} durch {{ .RedirectTo }} ersetzen musst.

Was du siehstWas du änderst
Jeder Link öffnet localhost:3000Die Site URL
Links öffnen deine Site URL statt der Adresse, die dein Code verlangt hatTrag diese Adresse in Redirect URLs ein, Zeichen für Zeichen
Die Live-Domain funktioniert, die veröffentlichte Adresse beim Builder nichtTrag die veröffentlichte Adresse in Redirect URLs ein
Ein Link öffnet deine Supabase-Adresse mit "No API key found in request"Setz https:// vor die Site URL
Die Adresse, die deine App verlangt, steht auf der Liste, und der Link übergeht sie trotzdemDas {{ .SiteURL }} in der E-Mail-Vorlage

Registrier dich dann noch einmal mit einer Adresse, die du noch nicht benutzt hast. Eine E-Mail, die vor der Korrektur mit Supabases Standardlink verschickt und innerhalb ihrer Stunde geöffnet wird, landet jetzt auf deiner Live-Seite, weil Supabase die Adresse beim Öffnen des Links noch einmal prüft. Das gilt, solange http://localhost:3000 nicht mehr auf deiner Liste steht.

Welche Redirect URLs kann man gefahrlos zulassen?

Die genauen Adressen, die dir gehören. Ein Platzhalter gehört zu Vorschau-Deployments, und nur beschränkt auf dein eigenes Team oder Projekt.

Supabases Anleitung zu Weiterleitungen sagt es klar: Der "Globstar" (**) sei für die lokale Entwicklung und für Vorschau-Adressen nützlich, in Produktion empfiehlt sie aber, für deine Site URL den genauen Weiterleitungspfad festzulegen.

Der Grund ist das, was mit der Person mitreist. Im Standardablauf schreibt Supabase die neue Sitzung in die Adresse, zu der es sie schickt: der Code, der sie baut, hängt #access_token=…&refresh_token=… an die Weiterleitungsadresse. Jede Seite unter dieser Adresse kann diese beiden Werte lesen, und mit ihnen ist sie dieser Nutzer. Beim Wegweiser entscheidet der Arm, wer den Schlüssel bekommt.

Ein Eintrag, der auf eine Adresse passt, die jemand anderes kontrolliert, ist also ein Weg in die Konten deiner Nutzer. Jeder kann dein Projekt bitten, einem deiner Nutzer einen Anmeldelink zu mailen, mit dem öffentlichen Schlüssel, der absichtlich in deiner App steht, und seine eigene Seite als Ziel angeben. Die E-Mail, die ankommt, stammt wirklich von deiner App. Der PKCE-Ablauf ändert daran nichts, weil die Person, die diesen Link geschrieben hat, die Anmeldung gestartet hat, und PKCE gibt die Sitzung dem, der sie gestartet hat.

Die Muster, die auf Adressen passen, die andere anlegen können:

  • ** allein passt auf jede Adresse, die es gibt.
  • https://*.vercel.app/** passt auf jedes Vercel-Deployment im Internet, und jeder kann eins anlegen. Supabases eigenes Beispiel enthält dein Team: https://*-<team-or-account-slug>.vercel.app/**.
  • https://*.lovable.app/**, https://*.netlify.app/** und dieselbe Form auf der Domain jedes Builders tun dasselbe für diesen Builder. Supabases Beispiel für Netlify ist ebenfalls beschränkt: https://**--my_org.netlify.app/**.
Ein genauer Eintrag schickt einen präparierten Link nach Hause. Ein Platzhalter, der auf die Apps anderer passt, lässt ihn die Anmeldung bei ihnen abliefern.

Wenn du das gerade mit einem eingefügten Platzhalter behoben hast, sieh dir die Liste heute noch einmal an.

Der Start ist auch der Moment, in dem die anderen Einstellungen, die erst in Produktion zählen, angeschaut werden. Unser kostenloser Scan liest deine Live-App von außen und meldet, was ein Fremder erreichen kann: Tabellen, die jedem antworten, geheime Schlüssel im Code, den deine App verschickt, fehlende Header, das Zertifikat. Er dauert etwa 20 Sekunden und braucht kein Konto: scanne deine App.

Die Live-App nach dem Start im Blick behalten

Diese Einstellung wird einmal korrigiert. Was deine App an Besucher schickt, ändert sich mit jedem Deploy, und dieser Teil lässt sich von außen beobachten.

Reeve Monitor prüft deine Live-App weiter:

  • ob sie erreichbar ist, alle 60 Sekunden, damit sich "der Link geht nicht" von "die Seite ist weg" unterscheiden lässt
  • alle neun Prüfungen jede Stunde, für bis zu drei Apps, einschließlich geheimer Schlüssel im Code, den deine App an Besucher schickt
  • eine Nachricht, wenn sich ein Ergebnis ändert, damit dich ein Problem, das mit einem späteren Deploy hinausgeht, erreicht, ohne dass du nachsehen musst
  • ein monatlicher Bericht in klarer Sprache über das, was er gesehen hat

Reeve Care hält eine Kopie deiner Supabase-Datenbank, samt Konten:

  • eine verschlüsselte Kopie nach Zeitplan, auf Reeves eigenem Speicher in der EU, außerhalb deines Supabase-Kontos
  • das Auth-Schema, in dem die Konten deiner Nutzer liegen, damit sie mit allem anderen zurückkommen
  • jede Kopie geprüft, bevor sie zählt, durch Zählen der Zeilen in jeder Tabelle
  • auch deine hochgeladenen Dateien, sobald du einen Storage-Zugang verbindest
  • eine Wiederherstellung per Klick, mit einer Sicherheitskopie des aktuellen Stands vorab
  • alles, was Monitor tut

Was du jetzt tun solltest

Was zu tun ist

  • Setz die Site URL auf der Seite URL Configuration auf deine Live-Adresse, https:// eingeschlossen.
  • Trag die anderen genauen Adressen, zu denen du Leute schickst, in Redirect URLs ein, etwa die Version mit www und die veröffentlichte Adresse beim Builder.
  • Sorg dafür, dass jede Adresse, die dein Code als emailRedirectTo oder redirectTo übergibt, auf der Liste steht, und nimm {{ .RedirectTo }} in Vorlagen, die ihr folgen sollen.
  • Sag allen, die nach der Registrierung auf der localhost-Seite gelandet sind, dass ihr Konto bestätigt ist. Magic Links und das Zurücksetzen von Passwörtern brauchen eine neue E-Mail.
  • Beschränk Platzhalter auf Vorschauen deines Teams und lass nie jede App auf der Domain eines Builders zu.

Wenn Leute den neuen Link drücken und hören, er sei abgelaufen, hat diese Meldung eine eigene Seite. Die 10-Minuten-Sicherheits-Checkliste deckt ab, was in einer frisch gestarteten App sonst oft offen bleibt.

FAQ

Warum öffnet meine Bestätigungs-E-Mail von Supabase localhost:3000?

Weil Supabase die Person zur Site URL deines Projekts geschickt hat, und die Site URL steht noch auf http://localhost:3000. Supabase nimmt sie immer dann, wenn die Adresse, die deine App verlangt hat, auf der Liste Redirect URLs fehlt oder deine App gar keine verlangt hat. Du änderst sie auf der Seite URL Configuration unter Authentication.

Ist das Konto bestätigt, wenn der Link localhost geöffnet hat?

Ja, bei einer Bestätigung der Registrierung. Supabase bestätigt die Adresse zuerst und schickt den Browser erst danach weiter, die gescheiterte Seite kommt also, wenn die Arbeit schon erledigt ist. Die Person kann sich auf deiner Live-Seite mit dem Passwort anmelden, das sie gewählt hat. Ein Magic Link oder ein Zurücksetzen des Passworts muss neu verschickt werden.

Ich habe meine Seite in Redirect URLs eingetragen, und es geht trotzdem auf localhost. Warum?

Der Eintrag muss Zeichen für Zeichen zu der Adresse passen, die Supabase angeboten wird: mit www oder ohne, mit https oder ohne, und der Pfad, denn ein Eintrag ohne /** am Ende passt nur auf genau diese eine Adresse. Passen sie und der Link übergeht sie trotzdem, baut deine E-Mail-Vorlage ihren Link aus {{ .SiteURL }}. Und korrigier die Site URL selbst, denn auf sie fällt alles andere zurück.

Muss ich meine Site URL in die Liste Redirect URLs eintragen?

Nein. Supabase nimmt jede Adresse auf der eigenen Domain der Site URL ohne Listeneintrag an, unter jedem Pfad. Die Liste ist für die anderen Adressen: eine Version mit www, die veröffentlichte Adresse beim Builder, Vorschau-Deployments.

Darf ich in Supabase Redirect URLs einen Platzhalter benutzen?

Für Vorschauen, beschränkt auf dein eigenes Team oder Projekt, wie in Supabases eigenen Beispielen. Nie einen, der auf Adressen passt, die andere anlegen können, etwa jede App auf vercel.app oder lovable.app. Supabase empfiehlt für deine Seite in Produktion die genaue Adresse.

Geschrieben von

Vlad Tkachenko

Gründer, Reeve

Ich schaue mir den ganzen Tag Apps an, die mit Lovable, Bolt, v0, Cursor und Replit gebaut wurden, und die kurze Liste von Fehlern, die darin immer wieder auftauchen.

Mehr über den Autor

Weiterlesen

Alle Artikel

Sichere deine Supabase-Datenbank vor der nächsten Änderung

Reeve sichert sie verschlüsselt nach Zeitplan und stellt sie für dich wieder her, wenn etwas schiefgeht.

Supabase-Backups ansehen

Automatisierte externe Prüfung, kein vollständiges Audit. Das Fehlen von Funden ist keine Garantie für Sicherheit.