[{"data":1,"prerenderedAt":1279},["ShallowReactive",2],{"blog-de-invalid-claim-missing-sub-claim":3,"blog-index-de":754},{"id":4,"title":5,"body":6,"category":712,"cover":713,"coverAlt":714,"description":715,"draft":716,"extension":717,"faq":718,"image":734,"keywords":735,"meta":742,"navigation":743,"ogTitle":744,"path":745,"published":746,"seo":747,"stem":748,"tldr":749,"updated":746,"__hash__":753},"blog_de\u002Fblog\u002Finvalid-claim-missing-sub-claim.md","Supabase \"invalid claim: missing sub claim\": niemand ist angemeldet",{"type":7,"value":8,"toc":699},"minimark",[9,13,24,36,41,44,59,77,83,86,97,103,107,110,119,129,135,142,148,174,182,186,189,203,211,219,226,236,260,265,269,272,283,332,343,346,350,353,362,368,384,390,404,408,411,430,437,447,451,454,569,588,592,598,607,621,631,648,652,684],[10,11,12],"p",{},"Deine App hat eine Supabase Edge Function, die etwas für die Person erledigt,\ndie sie benutzt, etwa ihre Einstellungen speichern oder in ihrem Auftrag OpenAI\naufrufen. Beim Testen hat sie funktioniert. Dann füllt sich das Log der Funktion\nmit dieser Zeile, und die App zeigt einen Fehler oder gar nichts:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","AuthApiError: invalid claim: missing sub claim\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26,27,30,31,35],{},"Such nach \"invalid claim: missing sub claim\", und man rät dir, deine Schlüssel\nneu zu erzeugen, Verify JWT abzuschalten oder den ",[21,28,29],{},"service_role","-Schlüssel\neinzusetzen. Jeder dieser Ratschläge behandelt das Token als kaputt. ",[32,33,34],"strong",{},"Das Token\nwar in Ordnung."," Supabase hat seine Signatur geprüft und es akzeptiert. Was ihm\nfehlte, war irgendein Name.",[37,38,40],"h2",{"id":39},"was-bedeutet-invalid-claim-missing-sub-claim","Was bedeutet \"invalid claim: missing sub claim\"?",[10,42,43],{},"Supabase Auth wurde gefragt, welcher Nutzer aufruft, fand das Token echt und\nfand keinen Nutzer darin eingetragen.",[10,45,46,47,50,51,58],{},"Die Tokens, die Supabase Auth liest, sind JWTs: drei Textblöcke, durch Punkte\ngetrennt, und der mittlere Block sind lesbare Daten. Jeder Eintrag in diesen\nDaten heißt Claim. ",[21,48,49],{},"sub",", kurz für Subject, ist der Claim, der die ID eines\nNutzers hält, und die\n",[52,53,57],"a",{"href":54,"rel":55},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fjwt-fields",[56],"nofollow","JWT-Referenz von Supabase","\nbeschreibt ihn als die Nutzer-ID, eine UUID.",[10,60,61,62,65,66,69,70,72,73,76],{},"Die Meldung steht im Quellcode von Supabase Auth selbst, in einer Funktion namens\n",[21,63,64],{},"maybeLoadUserOrSession"," in ",[21,67,68],{},"internal\u002Fapi\u002Fauth.go",". Wenn diese Funktion läuft,\nist die Signatur des Tokens schon geprüft und hat bestanden. Dann sucht sie nach\n",[21,71,49],{},", und wenn der Claim leer ist, bricht sie mit HTTP 403 ab, dem Fehlercode\n",[21,74,75],{},"bad_jwt"," und diesem Satz. Die Antwort, die dein Code bekommt, sieht so aus:",[14,78,81],{"className":79,"code":80,"language":19},[17],"{\"code\":403,\"error_code\":\"bad_jwt\",\"msg\":\"invalid claim: missing sub claim\"}\n",[21,82,80],{"__ignoreMap":23},[10,84,85],{},"Stell dir einen Empfang vor, dem eine einzige Frage gestellt wird: Welcher\nBesucher ist das? Du reichst einen Ausweis hin. Der Empfang prüft zuerst den\nStempel darauf, und der Stempel ist echt. Dann liest er die Namenszeile, und die\nNamenszeile ist leer. Der Empfang hat nichts, womit er antworten könnte, also\nlehnt er ab, und die Ablehnung nennt die leere Zeile.",[10,87,88,89,92,93,96],{},"Jeder Aufruf, der eine angemeldete Person braucht, kann diese Antwort bekommen.\n",[21,90,91],{},"getUser()"," und ",[21,94,95],{},"updateUser()"," sind die beiden, bei denen du sie am ehesten\nsiehst, und auch das Hinzufügen eines zweiten Faktors oder das Verknüpfen einer\nweiteren Anmeldemethode läuft durch dieselbe Prüfung.",[98,99],"diagram",{"alt":100,"caption":101,"src":102},"Zwei Ausweise gehen zum selben Empfang. Beide tragen ein echtes Siegel, und beide bestehen die Siegelprüfung. Der obere Ausweis, markiert mit authenticated, hat ein Gesicht und einen Namen, und der Empfang antwortet mit einer Person und 200. Der untere, markiert mit anon, hat ein leeres gestricheltes Foto und eine leere Namenszeile, und der Empfang antwortet mit 403.","Das Siegel wird zuerst geprüft, und beide Ausweise bestehen. Die Frage, an der es scheitert, ist die zweite: Wessen Name steht darauf?","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fthe-name-line-1600x720.png",[37,104,106],{"id":105},"ein-schlüssel-nennt-deine-app-ein-sitzungstoken-nennt-eine-person","Ein Schlüssel nennt deine App. Ein Sitzungstoken nennt eine Person.",[10,108,109],{},"Der API-Schlüssel deines Projekts ist der Ausweis mit der leeren Namenszeile,\nund er wurde absichtlich so gemacht.",[10,111,112,113,118],{},"Die ",[52,114,117],{"href":115,"rel":116},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fgetting-started\u002Fapi-keys",[56],"Dokumentation zu den API-Schlüsseln","\nsagt es in einer Zeile: Ein API-Schlüssel unterscheidet laut Supabase nicht\nzwischen Nutzern, sondern zwischen Anwendungen. Der Schlüssel sagt Supabase,\nwelche App aufruft. Wer diese App gerade benutzt, ist eine eigene Frage, und die\nbeantwortet ein Token, das Supabase Auth jeder Person bei der Anmeldung ausstellt.",[10,120,121,122,125,126,128],{},"Die JWT-Referenz von Supabase druckt beide ab. Der ",[21,123,124],{},"anon","-Schlüssel eines älteren\nProjekts ergibt entschlüsselt das hier, und nirgends steht ein ",[21,127,49],{},":",[14,130,133],{"className":131,"code":132,"language":19},[17],"{\n  \"iss\": \"supabase\",\n  \"ref\": \"abcdefghijklmnopqrst\",\n  \"role\": \"anon\",\n  \"iat\": 1640991600,\n  \"exp\": 1640995200\n}\n",[21,134,132],{"__ignoreMap":23},[10,136,137,138,141],{},"Das Zugriffstoken einer angemeldeten Person trägt ihre ID, die Rolle\n",[21,139,140],{},"authenticated"," und die Sitzung, zu der es gehört (hier gekürzt auf die Zeilen,\nauf die es ankommt):",[14,143,146],{"className":144,"code":145,"language":19},[17],"{\n  \"sub\": \"123e4567-e89b-12d3-a456-426614174000\",\n  \"role\": \"authenticated\",\n  \"session_id\": \"123e4567-e89b-12d3-a456-426614174000\",\n  \"email\": \"user@example.com\"\n}\n",[21,147,145],{"__ignoreMap":23},[10,149,150,151,153,154,157,158,160,161,92,164,167,168,173],{},"Der ",[21,152,29],{},"-Schlüssel ist wieder die erste Form, mit\n",[21,155,156],{},"\"role\": \"service_role\""," und weiterhin ohne ",[21,159,49],{},". Die neueren Schlüssel\n",[21,162,163],{},"sb_publishable_",[21,165,166],{},"sb_secret_"," sind gar keine JWTs, aber die\n",[52,169,172],{"href":170,"rel":171},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Fauth-error-401-invalid-claim-missing-sub--AFwMR",[56],"Fehlerseite von Supabase zu dieser Meldung","\nsagt, dass Auth sie erkennt und dass auch sie keinen sub-Claim tragen. Also\nerzeugt jeder Schlüssel deines Projekts, alt oder neu, öffentlich oder geheim,\ndiese Meldung, wenn er Auth übergeben wird, als wäre er eine Person. Dieselbe\nSeite nennt den Fehler beim Namen: versehentlich einen API-Schlüssel von Supabase\nzu benutzen statt des Zugriffstokens von Auth.",[10,175,176,177,181],{},"Wenn Schlüssel und ihre Präfixe neu für dich sind, erklärt\n",[52,178,180],{"href":179},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","welche API-Schlüssel in dein Frontend dürfen",",\nwie du den öffentlichen vom geheimen unterscheidest.",[37,183,185],{"id":184},"wo-der-schlüssel-statt-einer-sitzung-geschickt-wird","Wo der Schlüssel statt einer Sitzung geschickt wird",[10,187,188],{},"Drei Wege führen hierher, und der erste ist der, den eine Edge Function nimmt.",[10,190,191,194,195,198,199,202],{},[32,192,193],{},"1. Eine Edge Function, aufgerufen von einer Seite, auf der niemand angemeldet\nist."," Hat supabase-js eine Sitzung, legt es das Token der Person in den Header\n",[21,196,197],{},"Authorization",". Hat es keine, hat es nichts anderes für diesen Platz, also\nschickt es bei einem älteren Schlüssel stattdessen den Schlüssel deines Projekts\nin diesem Header. Seine Datei ",[21,200,201],{},"fetch.ts"," liest sich genau so: das Sitzungstoken,\nwenn es eins gibt, sonst der Schlüssel.",[10,204,205,206,210],{},"Die Plattformprüfung Verify JWT lässt diese Anfrage durch. Ein älterer Schlüssel\nist ein JWT, das dein Projekt signiert hat, und Supabase dokumentiert, dass die\nPrüfung auch die neueren Schlüssel annimmt. Genau diese Lücke erklärt\n",[52,207,209],{"href":208},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","einen geheimen Schlüssel in eine Edge Function verlegen","\nausführlich. Deine Funktion reicht den Header dann an Auth weiter, und das tun\ndiese Zeilen:",[14,212,217],{"className":213,"code":215,"language":216,"meta":23},[214],"language-ts","const supabase = createClient(\n  Deno.env.get('SUPABASE_URL')!,\n  Deno.env.get('SUPABASE_ANON_KEY')!,\n  { global: { headers: { Authorization: req.headers.get('Authorization')! } } },\n)\nconst { data: { user } } = await supabase.auth.getUser()\n","ts",[21,218,215],{"__ignoreMap":23},[10,220,221,222,225],{},"Auth liest den Schlüssel, findet die leere Namenszeile und antwortet mit 403.\nGibt die Funktion diesen Fehler zurück, zeigt deine App ",[21,223,224],{},"Edge Function returned a non-2xx status code",", und diese Meldung wartet im Log der Funktion.",[10,227,228,231,232,235],{},[32,229,230],{},"2. Ein Aufruf, bevor die Anmeldung fertig war."," Die Fehlerseite von Supabase\nnennt auch diesen Fall: ein Nutzer, der mit der Registrierung oder Anmeldung\nbegonnen und sie noch nicht abgeschlossen hatte, als ",[21,233,234],{},"getUser"," aufgerufen wurde.\nEine Form davon ist eine Registrierung, die noch auf ihre Bestätigungsmail\nwartet. Es gibt noch keine Sitzung, also war das, was bei Auth ankam, nicht das\nToken einer Person.",[10,237,238,241,242,245,246,249,250,253,254,256,257,259],{},[32,239,240],{},"3. Dein eigener Server reicht Auth den falschen Wert."," Eine Route, die\n",[21,243,244],{},"getUser(token)"," mit dem Schlüssel in ",[21,247,248],{},"token"," aufruft, oder eine Automation in\nn8n, Make oder Postman, die ",[21,251,252],{},"\u002Fauth\u002Fv1\u002Fuser"," mit dem Schlüssel im Header\n",[21,255,197],{}," aufruft. Die Lösung, die die Seite von Supabase für diesen Fall\nnennt: sicherstellen, dass das an ",[21,258,91],{}," übergebene Token das Zugriffstoken\nder Person ist.",[98,261],{"alt":262,"caption":263,"src":264},"Eine Seite, auf der niemand angemeldet ist, schickt zwei gleiche leere Ausweise, einen markiert mit apikey und einen mit Authorization. Beide bestehen die Prüfung der Plattform mit einem Haken und erreichen die Edge Function. Die Funktion reicht den Authorization-Ausweis an den Empfang weiter, der mit einem Kreuz und 403 antwortet.","Ist niemand angemeldet, schickt die Seite denselben Schlüssel in beiden Headern. Jede Prüfung vor Auth lässt ihn durch, und erst die Frage von Auth findet die Namenszeile leer.","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fthe-same-key-twice-1600x760.png",[37,266,268],{"id":267},"wie-du-siehst-was-deine-funktion-bekommen-hat","Wie du siehst, was deine Funktion bekommen hat",[10,270,271],{},"Vergleich zwei Request-Header in deinem Browser.",[10,273,274,275,278,279,282],{},"Öffne deine Live-App, drück F12, wähl den Tab ",[32,276,277],{},"Network"," und wiederhole, was\nfehlgeschlagen ist. Klick die Anfrage an, deren Adresse ",[21,280,281],{},"\u002Ffunctions\u002Fv1\u002F"," und den\nNamen deiner Funktion enthält, und lies ihre Request-Header:",[284,285,286,303,315],"ul",{},[287,288,289,302],"li",{},[32,290,291,293,294,297,298,301],{},[21,292,197],{}," enthält ",[21,295,296],{},"Bearer"," und danach dieselbe Zeichenkette wie\n",[21,299,300],{},"apikey","."," Die Seite hatte keine Sitzung zu schicken, also hat sie den\nSchlüssel zweimal geschickt. Du bist auf Weg 1 oder 2.",[287,304,305,314],{},[32,306,307,309,310,313],{},[21,308,197],{}," enthält eine andere lange Zeichenkette, die mit ",[21,311,312],{},"eyJ","\nbeginnt."," Das Token einer Person ist rausgegangen. Die Funktion oder dein\nServer hat es unterwegs verloren, also bist du auf Weg 3.",[287,316,317,322,323,327,328,331],{},[32,318,319,320,301],{},"Es gibt keinen Header ",[21,321,197],{}," Dann ist es nicht diese Meldung, die\ndu siehst. Mit eingeschaltetem Verify JWT lehnt die Plattform die Anfrage mit\n401 ab, bevor dein Code läuft, und\n",[52,324,326],{"href":325},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","der Beitrag zum non-2xx-Fehler","\nliest das. Ist es abgeschaltet, antwortet Auth mit ",[21,329,330],{},"This endpoint requires a valid Bearer token",", der ersten Zeile der Tabelle weiter unten.",[10,333,334,335,338,339,301],{},"Steht die Meldung stattdessen in der Konsole deines Browsers und lautet\n",[21,336,337],{},"Auth session missing!",", hat gar keine Anfrage Auth erreicht: supabase-js fand\nkeine Sitzung und hörte auf, bevor es eine schickte, und das behandelt\n",[52,340,342],{"href":341},"\u002Fblog\u002Fauth-session-missing","ein eigener Beitrag",[10,344,345],{},"Lies die Werte dort, wo sie stehen. Kopier keinen davon in eine Website, die\nanbietet, ihn zu entschlüsseln: Dein Schlüssel ist ohnehin öffentlich, aber mit\ndem Zugriffstoken einer Person kann jeder, der es hat, als diese Person handeln,\nbis es abläuft.",[37,347,349],{"id":348},"die-lösung-nur-fragen-wenn-jemand-angemeldet-ist","Die Lösung: nur fragen, wenn jemand angemeldet ist",[10,351,352],{},"Entscheide, was die Funktion für einen Besucher tun soll, der nicht angemeldet\nist, und schreib diese Entscheidung in die Funktion.",[10,354,355,358,359,361],{},[32,356,357],{},"Wenn nur angemeldete Personen sie benutzen sollen,"," zwei Änderungen. Die\nSeite ruft die Funktion erst auf, wenn sich jemand angemeldet hat. Und die\nFunktion antwortet mit einem klaren 401, wenn ",[21,360,91],{}," keinen Nutzer findet,\ndamit ein verirrter Aufruf von einer Seite ohne Anmeldung eine deutliche Absage\nbekommt statt eines Absturzes:",[14,363,366],{"className":364,"code":365,"language":216,"meta":23},[214],"const { data: { user } } = await supabase.auth.getUser()\nif (!user) {\n  return new Response(JSON.stringify({ error: 'Sign in first' }), {\n    status: 401,\n    headers: { ...corsHeaders, 'Content-Type': 'application\u002Fjson' },\n  })\n}\n",[21,367,365],{"__ignoreMap":23},[10,369,370,371,375,376,379,380,383],{},"Behalte die CORS-Header auch an dieser Antwort, sonst versteckt der Browser sie\nvor deiner App, und du triffst stattdessen auf\n",[52,372,374],{"href":373},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\"",".\nSupabase liefert außerdem einen Wrapper, ",[21,377,378],{},"withSupabase({ auth: 'user' })",", der\ndieselbe Prüfung macht, bevor dein Handler läuft; der\n",[52,381,382],{"href":208},"Beitrag zur Edge Function"," zeigt die\nEinrichtung.",[10,385,386,389],{},[32,387,388],{},"Wenn auch Besucher ohne Anmeldung sie benutzen sollen,"," frag Auth nur auf dem\nWeg, der eine Person braucht. Behandle eine Absage dort als \"das ist ein\nBesucher\" und mach mit dem weiter, was ein Besucher darf, statt die Anfrage am\nFehler scheitern zu lassen.",[10,391,392,395,396,399,400,403],{},[32,393,394],{},"Auf deinem eigenen Server"," schick das Zugriffstoken der Person aus dem\nBrowser mit, so wie es die Seite von Supabase beschreibt: Leg es in einen Header\n",[21,397,398],{},"Authorization: Bearer"," deiner Anfrage, lies es auf dem Server und ruf\n",[21,401,402],{},"supabase.auth.getUser(token)"," mit diesem Wert auf. Der Schlüssel deines Projekts\nkommt in diesen Aufruf nie hinein.",[37,405,407],{"id":406},"zwei-lösungen-nach-denen-du-schlechter-dastehst","Zwei Lösungen, nach denen du schlechter dastehst",[10,409,410],{},"Beide werden für diesen Fehler vorgeschlagen, und nach beiden stehst du\nschlechter da als mit dem Fehler.",[10,412,413,416,417,419,420,422,423,425,426,301],{},[32,414,415],{},"Den geheimen Schlüssel einsetzen."," Das kann nicht helfen, denn ",[21,418,29],{},"\nund ",[21,421,166],{}," tragen ebenfalls kein ",[21,424,49],{},", also antwortet Auth genauso. Der\nSchaden liegt darin, wo der Schlüssel landet. Bitte einen Builder, für einen\nFehler \"den Service-Schlüssel zu nehmen\", und gut möglich, dass er ihn in die\nSeite legt, die deine Besucher herunterladen. Dort liest und schreibt er jede\nZeile deiner Datenbank, egal was deine Regeln sagen. Ist das schon passiert,\n",[52,427,429],{"href":428},"\u002Fblog\u002Frotate-supabase-service-role-key","rotiere ihn zuerst",[10,431,432,433,301],{},"Dieses Versehen sieht man von außen. Unser kostenloser Scan liest das JavaScript\ndeiner Live-App so, wie ein Fremder es täte, und nennt jeden Schlüssel, den er\nfindet, samt der Frage, ob er dorthin gehört. Das dauert etwa 20 Sekunden und\nbraucht kein Konto: ",[52,434,436],{"href":435},"\u002Fsecurity-scanner","scanne deine App",[10,438,439,442,443,446],{},[32,440,441],{},"Die Prüfung löschen und die ID des Nutzers aus der Anfrage nehmen."," Eine\nFunktion, die ",[21,444,445],{},"userId"," aus dem Inhalt der Anfrage liest, glaubt jedem, der sie\nschickt. Schreibt diese Funktion außerdem mit dem geheimen Schlüssel, kann jeder,\nder deine Seite öffnet und nachliest, wie die Funktion aufgerufen wird, als jeder\ndeiner Nutzer handeln, und nichts in deinen Logs sagt, dass sie es nicht waren.\nBleibt die Prüfung drin, bekommt ein Fremder, der denselben Aufruf versucht,\ndiesen Fehler zurück und sonst nichts.",[37,448,450],{"id":449},"die-anderen-meldungen-derselben-prüfung","Die anderen Meldungen derselben Prüfung",[10,452,453],{},"Die Prüfungen von Auth laufen in fester Reihenfolge, und jede hat ihren eigenen\nSatz, also sagt dir die Meldung, wie weit das Token gekommen ist.",[455,456,457,473],"table",{},[458,459,460],"thead",{},[461,462,463,467,470],"tr",{},[464,465,466],"th",{},"Meldung",[464,468,469],{},"Status und Code",[464,471,472],{},"Was passiert ist",[474,475,476,495,510,524,539,554],"tbody",{},[461,477,478,483,489],{},[479,480,481],"td",{},[21,482,330],{},[479,484,485,486],{},"401 ",[21,487,488],{},"no_authorization",[479,490,491,492,494],{},"Es kam überhaupt kein Header ",[21,493,398],{}," an.",[461,496,497,502,507],{},[479,498,499],{},[21,500,501],{},"invalid JWT: unable to parse or verify signature, …",[479,503,504,505],{},"403 ",[21,506,75],{},[479,508,509],{},"Der Stempel stimmt nicht: ein beschädigtes Token, eins aus einem anderen Projekt oder ein alter Schlüssel.",[461,511,512,517,521],{},[479,513,514],{},[21,515,516],{},"invalid claim: missing sub claim",[479,518,504,519],{},[21,520,75],{},[479,522,523],{},"Der Stempel stimmt, und die Namenszeile ist leer: ein API-Schlüssel.",[461,525,526,531,536],{},[479,527,528],{},[21,529,530],{},"invalid claim: sub claim must be a UUID",[479,532,533,534],{},"400 ",[21,535,75],{},[479,537,538],{},"Ein Name steht da, aber nicht in der Form einer Nutzer-ID von Supabase.",[461,540,541,546,551],{},[479,542,543],{},[21,544,545],{},"User from sub claim in JWT does not exist",[479,547,504,548],{},[21,549,550],{},"user_not_found",[479,552,553],{},"Das Token nennt einen Nutzer, der inzwischen gelöscht wurde.",[461,555,556,561,566],{},[479,557,558],{},[21,559,560],{},"Session from session_id claim in JWT does not exist",[479,562,504,563],{},[21,564,565],{},"session_not_found",[479,567,568],{},"Das Token hat seine Sitzung überlebt, zum Beispiel nach einer Abmeldung auf einem anderen Gerät.",[10,570,571,572,574,575,578,579,583,584,301],{},"Jede Zeile stammt aus derselben Datei, ",[21,573,68],{},". Die Version der\nZeile mit dem falschen Stempel, die deine Datenbank selbst meldet, ",[21,576,577],{},"PGRST301",",\nhat ",[52,580,582],{"href":581},"\u002Fblog\u002Fsupabase-invalid-jwt","einen eigenen Beitrag",". Die Zeile zur Sitzung\nliest du am besten zusammen mit\n",[52,585,587],{"href":586},"\u002Fblog\u002Fsupabase-users-logged-out","warum Supabase-Nutzer abgemeldet werden",[37,589,591],{"id":590},"damit-die-prüfung-nach-der-nächsten-änderung-bleibt","Damit die Prüfung nach der nächsten Änderung bleibt",[10,593,594,597],{},[32,595,596],{},"Eine Prüfung, wer da aufruft, kann verschwinden, wenn du deinen Builder das\nnächste Mal bittest, einen Fehler wegzumachen",", und die zwei schnellsten Wege,\ndiesen hier zum Schweigen zu bringen, sind die beiden oben.",[10,599,600],{},[32,601,602,606],{},[52,603,605],{"href":604},"\u002Fwebsite-monitoring","Reeve Monitor"," scannt deine Live-App jede Stunde neu:",[284,608,609,612,615,618],{},[287,610,611],{},"alle neun Checks jede Stunde, für bis zu drei Apps",[287,613,614],{},"eine E-Mail an dem Tag, an dem ein erneuter Scan deine App schlechter benotet als der vorige; ein geheimer Schlüssel in deinem JavaScript deckelt die Note allein schon bei D",[287,616,617],{},"ob die App erreichbar ist, alle 60 Sekunden",[287,619,620],{},"ein monatlicher Bericht darüber, was gesehen wurde",[10,622,623],{},[32,624,625,626,630],{},"Eine Funktion, die der Nutzer-ID glaubt, die man ihr schickt, kann für jeden,\nder sie aufruft, die Zeilen jedes deiner Nutzer ändern.\n",[52,627,629],{"href":628},"\u002Fsupabase-backups","Reeve Care"," hält eine Kopie deiner Supabase-Datenbank von\ndavor.",[284,632,633,636,639,642,645],{},[287,634,635],{},"eine verschlüsselte Kopie nach Zeitplan, auf Reeves eigenem Speicher in der EU, außerhalb deines Supabase-Kontos",[287,637,638],{},"jede Kopie wird geprüft, bevor sie zählt, durch Zählen der Zeilen in jeder Tabelle",[287,640,641],{},"eine Wiederherstellung per Klick, die sichert, was jetzt da ist, bevor sie es ersetzt",[287,643,644],{},"deine hochgeladenen Dateien ebenfalls, sobald du eine Storage-Zugangsberechtigung verbindest",[287,646,647],{},"alles, was Monitor tut",[37,649,651],{"id":650},"was-jetzt-zu-tun-ist","Was jetzt zu tun ist",[653,654,655],"key-takeaways",{},[284,656,657,666,672,678,681],{},[287,658,659,660,662,663,665],{},"Öffne die fehlgeschlagene Anfrage im Tab Network. Trägt ",[21,661,197],{}," denselben Wert wie ",[21,664,300],{},", war beim Abschicken niemand angemeldet.",[287,667,668,669,671],{},"Ruf Funktionen, die eine Person brauchen, erst nach der Anmeldung auf, und lass die Funktion mit 401 antworten, wenn ",[21,670,91],{}," keinen Nutzer findet.",[287,673,674,675,677],{},"Übergib auf deinem eigenen Server das Zugriffstoken der Person an ",[21,676,91],{},". Im Schlüssel deines Projekts steht kein Nutzer.",[287,679,680],{},"Lass den geheimen Schlüssel, wo er ist. Auch er nennt niemanden, und in der Seite liest und schreibt er jede Zeile.",[287,682,683],{},"Behalte die Prüfung, wer da aufruft. Eine Funktion, die die ID des Nutzers aus der Anfrage nimmt, glaubt jedem.",[10,685,686,687,689,690,693,694,698],{},"Zeigt deine App ",[21,688,224],{},", während diese\nMeldung im Log steht, reicht die Funktion die Absage weiter, und\n",[52,691,692],{"href":325},"dieser Beitrag"," liest die\nAntwort von dort aus weiter. Die ",[52,695,697],{"href":696},"\u002Fchecklist","10-Minuten-Sicherheitscheckliste","\ndeckt ab, was in einer frisch gestarteten App sonst gern offen bleibt.",{"title":23,"searchDepth":700,"depth":700,"links":701},3,[702,704,705,706,707,708,709,710,711],{"id":39,"depth":703,"text":40},2,{"id":105,"depth":703,"text":106},{"id":184,"depth":703,"text":185},{"id":267,"depth":703,"text":268},{"id":348,"depth":703,"text":349},{"id":406,"depth":703,"text":407},{"id":449,"depth":703,"text":450},{"id":590,"depth":703,"text":591},{"id":650,"depth":703,"text":651},"Sicherheitsgrundlagen","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcover-1200x630.png","Ein Ausweis am Schlüsselband mit echtem Siegel und leerer Namenszeile, vor zwei Ausweisen mit Namen und Gesicht.","\"invalid claim: missing sub claim\" heißt: Supabase Auth bekam ein echtes Token ohne Nutzer darin, deinen Projektschlüssel statt einer Sitzung.",false,"md",[719,722,725,728,731],{"q":720,"a":721},"Was bedeutet \"invalid claim: missing sub claim\" in Supabase?","Es heißt, dass Supabase Auth gefragt wurde, welcher Nutzer aufruft, und ein Token ohne Nutzer darin bekam. Das Token selbst war echt und hat die Signaturprüfung bestanden. Es fehlte der Claim sub, das Feld, in dem die ID eines Nutzers steht. Genau so sehen die API-Schlüssel deines Projekts aus, und deshalb ist die übliche Ursache ein Schlüssel, der dort geschickt wurde, wo das Token eines angemeldeten Nutzers hingehört.",{"q":723,"a":724},"Ist das dasselbe wie \"Auth session missing!\"?","Nein. \"Auth session missing!\" kommt von supabase-js im Browser, das keine Sitzung findet und die Anfrage gar nicht erst abschickt. \"invalid claim: missing sub claim\" kommt von Supabase Auth zurück, das eine Anfrage bekommen und einen Schlüssel gefunden hat, wo das Token des Nutzers sein sollte. Das Erste heißt meist: eine Seite ohne Anmeldung. Das Zweite heißt meist: Eine Funktion oder ein Server hat den Schlüssel weitergereicht.",{"q":726,"a":727},"Verschwindet der Fehler, wenn ich Verify JWT abschalte?","Nein. Verify JWT ist eine Prüfung, die Supabase bei einer Edge Function ausführt, bevor dein Code startet, und diese Meldung kommt später, von Supabase Auth, wenn dein Code fragt, wer da aufruft. Schaltest du die Plattformprüfung ab, erreichen auch Anfragen ganz ohne Token deinen Code, und dieser Fehler bleibt genau, wo er war.",{"q":729,"a":730},"Löst eine anonyme Anmeldung diesen Fehler aus?","Nein. Eine anonyme Anmeldung legt einen echten Nutzer mit eigener ID an, also trägt sein Token einen sub-Claim und is_anonymous auf true. Der anon-Schlüssel ist etwas anderes mit ähnlichem Namen: ein Projektschlüssel ohne Nutzer darin, und er ist es, der diese Meldung erzeugt.",{"q":732,"a":733},"Warum steht auf manchen Seiten 401 und auf anderen 403?","Die Fehlerseite von Supabase zu dieser Meldung hat 401 im Titel. Der aktuelle Code von Supabase Auth antwortet mit 403 und dem Fehlercode bad_jwt. Wenn dein Code allein am Status entscheidet, was er tut, prüf auch den Fehlercode und die Meldung.","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",[736,516,737,738,739,740,741],"invalid claim missing sub claim supabase","AuthApiError invalid claim missing sub claim","bad_jwt supabase","supabase getuser 403","supabase edge function getuser fehler","supabase anon key getuser",{},true,"\"invalid claim: missing sub claim\" in Supabase","\u002Fblog\u002Finvalid-claim-missing-sub-claim","2026-11-04",{"title":5,"description":715},"blog\u002Finvalid-claim-missing-sub-claim",[750,751,752],"\"invalid claim: missing sub claim\" ist Supabase Auth, das mit 403 und dem Code bad_jwt antwortet. Es wurde gefragt, wer da aufruft, das Token war echt, und es nannte niemanden.","Die eigene Fehlerseite von Supabase nennt die häufige Ursache: ein API-Schlüssel, geschickt an der Stelle, an die das Zugriffstoken eines angemeldeten Nutzers gehört. Ein Schlüssel sagt, welche App aufruft, und enthält keine Person.","Ruf die Funktion erst auf, wenn jemand angemeldet ist, und lass sie mit 401 antworten, wenn niemand angemeldet ist. Den geheimen Schlüssel einzusetzen ändert nichts, denn auch er nennt niemanden.","feecYQXufzUdiRWHxUDR_ZzNw_D4bZDEfSvU1XD2qvg",[755,761,767,773,779,784,785,790,796,802,808,815,821,827,832,838,844,850,856,862,868,874,879,885,891,896,902,908,914,920,926,932,938,944,950,956,961,967,973,979,985,991,997,1003,1009,1015,1020,1026,1032,1038,1044,1050,1056,1062,1068,1074,1080,1086,1092,1098,1104,1110,1116,1122,1127,1133,1139,1145,1151,1157,1163,1169,1175,1181,1187,1193,1199,1205,1211,1217,1223,1229,1235,1241,1246,1252,1258,1264,1269,1275],{"path":756,"title":757,"description":758,"published":759,"category":712,"image":760,"draft":716},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\" erklärt","Supabase \"max client connections reached\": Der Pooler hat keinen Platz für noch einen Client. Der Port in deinem Connection String setzt das Limit.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":762,"title":763,"description":764,"published":765,"category":712,"image":766,"draft":716},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Supabase-Fehler: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\" heißt: Google-Login ist in deinem Supabase-Projekt aus. Die Lösung, und was bei redirect_uri_mismatch hilft.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":768,"title":769,"description":770,"published":771,"category":712,"image":772,"draft":716},"\u002Fblog\u002Fviolates-foreign-key-constraint","Supabase-Fehler \"violates foreign key constraint\" beim Einfügen","Supabase \"insert or update on table violates foreign key constraint\": Deine Zeile zeigt auf eine, die es nicht gibt. Welche, warum, und die Lösung.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":774,"title":775,"description":776,"published":777,"category":712,"image":778,"draft":716},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Supabase-Fehler \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": Eine Pflichtspalte kam leer an. Woher die Null kommt, und die Lösung.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":341,"title":780,"description":781,"published":782,"category":712,"image":783,"draft":716},"Supabase \"Auth session missing!\": wo die Sitzung geblieben ist","\"Auth session missing!\" heißt: supabase-js fand keine angemeldete Sitzung und fragte Supabase gar nicht erst. Wo die Sitzung blieb, und die Lösung je Fall.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":745,"title":5,"description":715,"published":746,"category":712,"image":734,"draft":716},{"path":373,"title":786,"description":787,"published":788,"category":712,"image":789,"draft":716},"\"Failed to send a request to the Edge Function\": der echte Grund","\"Failed to send a request to the Edge Function\" heißt: Der Browser hat keine lesbare Antwort bekommen. Seine Konsole sagt, warum, und ob deine Funktion lief.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":791,"title":792,"description":793,"published":794,"category":712,"image":795,"draft":716},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","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.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":797,"title":798,"description":799,"published":800,"category":712,"image":801,"draft":716},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" bei einem neuen Link","Bei einem Link von vor einer Minute heißt Supabases \"Email link is invalid or has expired\" meist: Ein Mailfilter hat ihn zuerst benutzt. Prüfen und beheben.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":803,"title":804,"description":805,"published":806,"category":712,"image":807,"draft":716},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\" erklärt","Supabase \"canceling statement due to statement timeout\": Eine Abfrage lief länger als ihre Rolle darf, 3 Sekunden für Besucher. Prüf zuerst die RLS-Regel.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":809,"title":810,"description":811,"published":812,"category":813,"image":814,"draft":716},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" in Supabase und was mitgelöscht wird","\"Database error deleting user\" in Supabase heißt: Deine Datenbank hat das Löschen abgelehnt. Der Grund steht im Log, die Lösung entscheidet, was mitgeht.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":816,"title":817,"description":818,"published":819,"category":712,"image":820,"draft":716},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" bei Supabase","Ein Stripe-Webhook in einer Supabase Edge Function meldet \"No signatures found matching the expected signature\"? Zwei Ursachen. Prüfe weiter.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":822,"title":823,"description":824,"published":825,"category":712,"image":826,"draft":716},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" in Supabase: die drei Ursachen","Supabase sagt \"Invalid login credentials\" bei falschem Passwort, unbekannter E-Mail und Google-Konto. So erkennst du, welcher Fall es ist.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":325,"title":828,"description":829,"published":830,"category":712,"image":831,"draft":716},"\"Edge Function returned a non-2xx status code\": der echte Fehler","\"Edge Function returned a non-2xx status code\" heißt: Deine Supabase-Funktion hat mit einem Fehler geantwortet. So liest du den echten.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":833,"title":834,"description":835,"published":836,"category":712,"image":837,"draft":716},"\u002Fblog\u002Fcertificate-not-trusted","Zertifikat nicht vertrauenswürdig: drei Ursachen außer Ablauf","Zertifikat nicht vertrauenswürdig, obwohl das Datum stimmt? Es nennt eine andere Adresse, hat sich selbst signiert oder seiner Kette fehlt ein Glied.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":839,"title":840,"description":841,"published":842,"category":712,"image":843,"draft":716},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": was im Zitat steht","Supabase \"invalid input syntax for type uuid\" heißt: Deine App hat etwas geschickt, das keine ID ist. Zitat lesen, Abfrage zurückhalten, Spalte behalten.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":845,"title":846,"description":847,"published":848,"category":712,"image":849,"draft":716},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\" erklärt","Supabase \"duplicate key value violates unique constraint\" heißt: Der Wert ist schon vergeben. Spalte finden, Lösung wählen, Wert vom Bildschirm fernhalten.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":851,"title":852,"description":853,"published":854,"category":712,"image":855,"draft":716},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\", obwohl die Tabelle da ist","Supabase \"relation does not exist\" oder PGRST205: Keine Tabelle passt zu Name und Schema deiner Abfrage. Vier Prüfungen, und was eine Freigabe öffnet.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":857,"title":858,"description":859,"published":860,"category":712,"image":861,"draft":716},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" nennt die Argumente, die deine App geschickt hat. Vergleich sie mit der Funktion.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":863,"title":864,"description":865,"published":866,"category":712,"image":867,"draft":716},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" heißt meist: Der Name passt nicht. Vier Prüfungen und der Einzeiler zum Neuladen.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":869,"title":870,"description":871,"published":872,"category":712,"image":873,"draft":716},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": zwei Limits, ein Fehlercode","Supabase \"Email Rate Limit Exceeded\" begrenzt jede E-Mail deines Projekts: 2 pro Stunde beim eingebauten Absender. Was zählt und wie du es anhebst.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":586,"title":875,"description":876,"published":877,"category":712,"image":878,"draft":716},"Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 Ursachen","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" meldet deine Nutzer ab. Drei Ursachen, und wie das Auth-Log sie trennt.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":880,"title":881,"description":882,"published":883,"category":712,"image":884,"draft":716},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": drei Ursachen","Supabase \"permission denied for schema public\" heißt: Ein Grant auf das Schema fehlt. Was ihn entfernt hat und welche Zeile ihn zurückbringt.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":886,"title":887,"description":888,"published":889,"category":712,"image":890,"draft":716},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": die drei Dinge, die es bedeutet","Supabase \"Bucket not found\" ist eins von drei Dingen: ein öffentlicher Link zu einem privaten Bucket, ein ungenauer Name oder das falsche Projekt.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":581,"title":892,"description":893,"published":894,"category":712,"image":895,"draft":716},"Supabase invalid JWT: Welcher Schlüssel streikt hier?","Ein Supabase invalid JWT ist PGRST301: ein signiertes Token hat die Prüfung nicht bestanden. In neueren Projekten ist das die Sitzung, nicht der API-Schlüssel.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":897,"title":898,"description":899,"published":900,"category":712,"image":901,"draft":716},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" heißt meist: keine Zeilen","Supabase gibt PGRST116 zurück, \"JSON object requested, multiple (or no) rows returned\", wenn die Abfrage nichts fand. Versteckte Zeilen wirken fehlend.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":903,"title":904,"description":905,"published":906,"category":712,"image":907,"draft":716},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" in Supabase: wo du nachsiehst","\"Database error saving new user\" heißt: etwas an deiner Supabase-Registrierung ist fehlgeschlagen. Der echte Fehler steht in deinen Logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":909,"title":910,"description":911,"published":912,"category":712,"image":913,"draft":716},"\u002Fblog\u002Fwhat-is-supabase","Was ist Supabase? Die Datenbank, die dein Builder ausgesucht hat","Was ist Supabase: die Datenbank, der Login und der Dateispeicher hinter deiner App. Supabase betreibt die Server, die Regeln zu deinen Zeilen gehören dir.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":915,"title":916,"description":917,"published":918,"category":712,"image":919,"draft":716},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Ein offengelegter AWS-Schlüssel im Frontend ist kein OpenAI-Key","Ein im Frontend offengelegter AWS-Zugriffsschlüssel liest und schreibt deinen Speicher. Die Lösung ist meist eine presigned URL, kein neuer Schlüssel.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":921,"title":922,"description":923,"published":924,"category":712,"image":925,"draft":716},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" beim Upload","\"New row violates row-level security policy for table objects\" heißt: Deinem Upload fehlt eine insert-Regel. Ein öffentlicher Bucket fügt keine hinzu.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":927,"title":928,"description":929,"published":930,"category":712,"image":931,"draft":716},"\u002Fblog\u002Fbase44-security-scan","Base44 Security Scan: das, was nur er sehen kann","Der Base44 Security Scan prüft sieben Arten von Problemen von innen. Hier ist die Hälfte, die er liest und sonst niemand, und die Hälfte, die er nie ansieht.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":933,"title":934,"description":935,"published":936,"category":712,"image":937,"draft":716},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Dein API-Key wurde geleakt. Die richtige Reihenfolge","Ein API-Key wurde geleakt und du weißt nicht, was zuerst zu tun ist. Nicht jeder Key im Frontend ist ein Leck, und die Reihenfolge zählt mehr als das Tempo.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":939,"title":940,"description":941,"published":942,"category":712,"image":943,"draft":716},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" ohne RLS abzuschalten","\"Infinite recursion detected in policy for relation\" heißt: Deine Policy hat die Tabelle gefragt, die sie schützt. So brichst du den Kreis.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":945,"title":946,"description":947,"published":948,"category":712,"image":949,"draft":716},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" in Supabase, und die falsche Lösung","\"No API key found in request\" heißt, deine Supabase-Anfrage kam ohne Schlüssel an. Die meisten Antworten zeigen stattdessen auf deine Datenbankregeln.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":951,"title":952,"description":953,"published":954,"category":712,"image":955,"draft":716},"\u002Fblog\u002Fis-base44-safe","Ist Base44 sicher? Was 5.442 echte Base44-Apps zeigten","Ist Base44 sicher? Wir haben 5.442 laufende Base44-Apps mit neun Checks geprüft. Fast alle bekamen ein B, aus Gründen, die der Inhaber nie gewählt hat.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":208,"title":957,"description":958,"published":959,"category":712,"image":960,"draft":716},"API-Schlüssel verstecken: ab in eine Supabase Edge Function","Einen API-Schlüssel verstecken heißt, ihn aus dem Browser zu nehmen. Eine Supabase Edge Function ist der kleinste Ort dafür, und zwei Schritte zählen mehr.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":962,"title":963,"description":964,"published":965,"category":712,"image":966,"draft":716},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Ist deine .env-Datei öffentlich? Zwölf Pfade zum Prüfen","Ist deine .env-Datei auf deinem eigenen Webserver öffentlich? Zwölf Adressen sagen es dir, und ein Treffer heißt: alles darin ist längst öffentlich.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":968,"title":969,"description":970,"published":971,"category":712,"image":972,"draft":716},"\u002Fblog\u002Fis-v0-safe","v0-Sicherheit: alle 1.790 gescannten v0-Apps bekamen ein A","v0-Sicherheit, gemessen an 1.790 laufenden v0-Apps: Jede bekam ein A. Nur 17 nannten eine Datenbank, und genau das misst das A vor allem.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":974,"title":975,"description":976,"published":977,"category":712,"image":978,"draft":716},"\u002Fblog\u002Fis-bolt-safe","Ist Bolt sicher? Was 1.123 echte Bolt-Apps zeigten","Ist Bolt sicher? Wir haben 1.123 laufende Bolt-Apps mit neun Checks geprüft. Das Hosting war sauber. Die Funde waren Schlüssel und offene Tabellen in den Apps.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":980,"title":981,"description":982,"published":983,"category":712,"image":984,"draft":716},"\u002Fblog\u002Fis-supabase-down-or-your-app","Ist Supabase down oder liegt es an deiner App? So erkennst du es","Ist Supabase down oder liegt es an deiner App? Ein pausiertes Projekt, eine volle Datenbank und ein eigener Fehler sehen gleich aus. Vier Prüfungen helfen.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":986,"title":987,"description":988,"published":989,"category":712,"image":990,"draft":716},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Verschlüsselt Supabase meine Daten? Ja. Wovor das schützt","Verschlüsselt Supabase Daten? Ja: AES-256 im Ruhezustand, TLS bei der Übertragung, SOC 2 und ISO 27001. Was jedes abdeckt und welches Leck keines stoppt.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":992,"title":993,"description":994,"published":995,"category":712,"image":996,"draft":716},"\u002Fblog\u002Fsupabase-free-plan-limits","Supabase Gratis-Tarif: die Limits und was an jedem passiert","Die Limits des Supabase-Gratis-Tarifs: 500 MB Datenbank, 5 GB Egress und keine Backups. Was an jeder Grenze passiert und was $25 für Pro ändern.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":998,"title":999,"description":1000,"published":1001,"category":813,"image":1002,"draft":716},"\u002Fblog\u002Ftest-your-supabase-backup","Teste dein Supabase-Backup, bevor du es brauchst","So testest du dein Supabase-Backup: in ein Übungsprojekt einspielen, Zeilen zählen, anmelden und die Zeile suchen, die einer abgeschnittenen Datei fehlt.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":1004,"title":1005,"description":1006,"published":1007,"category":813,"image":1008,"draft":716},"\u002Fblog\u002Fsupabase-backup-github-action","Kostenloses Supabase-Backup per GitHub Action, mit Haken","Eine Supabase-Backup-GitHub-Action kostet nichts und passt für viele Apps. Der Workflow, der richtige Connection String und das Egress pro Lauf.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":1010,"title":1011,"description":1012,"published":1013,"category":813,"image":1014,"draft":716},"\u002Fblog\u002Fdownload-your-supabase-backup","Warum du dein Supabase-Backup nicht herunterladen kannst","Dein Supabase-Backup kannst du auf aktuellen Projekten nicht herunterladen, weil die Tageskopie physisch ist. Wie du es prüfst und selbst eine Kopie hältst.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":1016,"title":1017,"description":1018,"published":1013,"category":712,"image":1019,"draft":716},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": der fehlende Grant","Ab 30. Oktober antwortet eine neue Supabase-Tabelle mit \"permission denied for table\", bis du Zugriff erteilst. Der Grant aus der E-Mail ist die halbe Lösung.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":1021,"title":1022,"description":1023,"published":1024,"category":712,"image":1025,"draft":716},"\u002Fblog\u002Fopen-api-endpoint-exposed","Ist ein offener API-Endpunkt ein Sicherheitsproblem? Sieh ins JSON","Dein Scan hat einen offenen API-Endpunkt gemeldet. Ob das zählt, hängt davon ab, was zurückkam, und die meisten hier gehörten der Plattform.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":1027,"title":1028,"description":1029,"published":1030,"category":712,"image":1031,"draft":716},"\u002Fblog\u002Flovable-security-scan","Lovable Security Scan: das Eine, was er nicht beweist","Lovable Security Scan: was Quick Scan und Deep Scan prüfen, wann welcher läuft, und das Eine, was kein Scan von innen beweisen kann.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":1033,"title":1034,"description":1035,"published":1036,"category":813,"image":1037,"draft":716},"\u002Fblog\u002Fsupabase-backup-auth-users","Warum in deinem Supabase-Dump keine Nutzer stehen","Führe supabase db dump allein aus und du bekommst die Form deiner Datenbank und keine einzige Zeile, und das auth-Schema mit deinen Nutzern fehlt ganz.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":1039,"title":1040,"description":1041,"published":1042,"category":712,"image":1043,"draft":716},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domain abgelaufen, Website offline: was jetzt passiert","Deine Domain ist abgelaufen und deine Website ist offline. Welche Frist jetzt läuft, warum das Zertifikat das kleinere Problem ist, und wie du beides prüfst.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":1045,"title":1046,"description":1047,"published":1048,"category":712,"image":1049,"draft":716},"\u002Fblog\u002Fis-lovable-safe","Ist Lovable sicher? Was 18.554 echte Lovable-Apps zeigten","Ist Lovable sicher? Wir haben 18.554 laufende Lovable-Apps mit neun Checks geprüft. Die Plattform war die sauberste von fünf. Die Funde saßen in den Apps.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":1051,"title":1052,"description":1053,"published":1054,"category":712,"image":1055,"draft":716},"\u002Fblog\u002Fvibe-coded-app-security-checklist","Die Sicherheits-Checkliste für Vibe-Coding, in neun Prüfungen","Eine Sicherheits-Checkliste für Vibe-Coding mit neun Punkten, die jeder von außen an deiner Live-App nachprüfen kann, jeder mit einem Test in einer Zeile.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":1057,"title":1058,"description":1059,"published":1060,"category":712,"image":1061,"draft":716},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Ein geheimer Stripe-Schlüssel im Frontend kann Geld bewegen","Ein geheimer Stripe-Schlüssel im Frontend kann erstatten, abbuchen und jeden Kundendatensatz lesen, den du hast. Dein pk_live_-Schlüssel gehört dorthin.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":1063,"title":1064,"description":1065,"published":1066,"category":712,"image":1067,"draft":716},"\u002Fblog\u002Fvite-and-next-public-env-vars","Vite-Env-Variablen offengelegt: der Präfix heißt veröffentlichen","Vite-Env-Variablen offengelegt: Deine App hat getan, was der Präfix verlangt. VITE_ und NEXT_PUBLIC_ heißen veröffentlichen, und die KI kannte den Preis nie.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":1069,"title":1070,"description":1071,"published":1072,"category":712,"image":1073,"draft":716},"\u002Fblog\u002Fbase44-source-maps","Base44-Sicherheit: was ein Scan meldet und was du ändern kannst","Base44-Sicherheit auf 5.438 gescannten Apps: Drei Befunde auf fast jeder gehören der Plattform, die Source Map ist das Base44-Badge, und deine Liste ist kurz.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":1075,"title":1076,"description":1077,"published":1078,"category":712,"image":1079,"draft":716},"\u002Fblog\u002Fis-cursor-ai-safe","Ist Cursor AI sicher? Editor, Code und die App, die du veröffentlichst","Ist Cursor AI sicher? Drei Fragen in einer Suche: was Cursor behält, was sein Code falsch macht und ob deine veröffentlichte App offen steht.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":1081,"title":1082,"description":1083,"published":1084,"category":712,"image":1085,"draft":716},"\u002Fblog\u002Fis-replit-safe","Ist Replit sicher? Was wir in 3.042 Replit-Apps gefunden haben","Ist Replit sicher? Wir haben 3.042 laufende Replit-Apps mit neun externen Checks geprüft. Die Funde saßen in der veröffentlichten App, nicht im Hosting.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":1087,"title":1088,"description":1089,"published":1090,"category":813,"image":1091,"draft":716},"\u002Fblog\u002Fsupabase-storage-backup","Supabase Storage Backup: deine Datenbankkopie hat keine Dateien","Ein Supabase Storage Backup ist eine eigene Aufgabe. Datenbank-Backups enthalten die Liste deiner Dateien und keine davon, also bleibt jeder Upload kaputt.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1093,"title":1094,"description":1095,"published":1096,"category":813,"image":1097,"draft":716},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Supabase Point-in-Time Recovery: Kosten und Grenzen","Supabase Point-in-Time Recovery spult deine Datenbank auf jede Sekunde der letzten Woche zurück. $100 im Monat zusätzlich zu Pro, und nur die Datenbank.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1099,"title":1100,"description":1101,"published":1102,"category":813,"image":1103,"draft":716},"\u002Fblog\u002Fsupabase-project-paused-recover","Supabase-Projekt pausiert? Deine Daten sind noch da","Supabase hat dein Projekt nach einer Woche ohne Aktivität pausiert. Gelöscht ist nichts, Wiederherstellen steht neben dem Namen, und du hast ein Jahr.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1105,"title":1106,"description":1107,"published":1108,"category":712,"image":1109,"draft":716},"\u002Fblog\u002Fsafest-ai-app-builder","Welcher KI-App-Builder ist am sichersten? 30.998 Apps im Test","Welcher KI-App-Builder ist am sichersten? Wir haben 30.998 aktive Apps von Lovable, Base44, Replit, v0 und Bolt gescannt. Der Builder entscheidet das nicht.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":1111,"title":1112,"description":1113,"published":1114,"category":712,"image":1115,"draft":716},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Row Level Security für jede Supabase-Tabelle aktivieren und prüfen","Row Level Security in Supabase ohne Policy sperrt eine Tabelle komplett. Eine Policy ohne den Schalter bringt gar nichts. Hier ist das SQL, und der Test.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":1117,"title":1118,"description":1119,"published":1120,"category":712,"image":1121,"draft":716},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": was die Warnung übersieht","Supabase meldet \"RLS disabled in public\" als Fehler. Zur Lese-Policy, die deine Tabelle genauso offen lässt, sagt der Advisor gar nichts.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":428,"title":1123,"description":1124,"published":1125,"category":712,"image":1126,"draft":716},"Geleakten Supabase-service_role-Schlüssel richtig tauschen","Supabase sagt: erst das Leck schließen. Andere Anleitungen: sofort tauschen. Was richtig ist, hängt davon ab, wohin dein service_role-Schlüssel gelangt ist.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1128,"title":1129,"description":1130,"published":1131,"category":712,"image":1132,"draft":716},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Vibe-Coding-Security-Scanner im Vergleich, unserer eingeschlossen","Der beste Vibe-Coding-Security-Scanner hängt an drei Fragen, die keine Funktionsliste beantwortet. Acht Tools im Vergleich, mit Preisen und unseren Lücken.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1134,"title":1135,"description":1136,"published":1137,"category":712,"image":1138,"draft":716},"\u002Fblog\u002Fsupabase-security-checker","Supabase Security Checker: die fünf Prüfungen selbst machen","Ein Supabase Security Checker liest deine veröffentlichte App statt deiner Projekteinstellungen. Hier sind die fünf Prüfungen und wie du jede selbst ausführst.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1140,"title":1141,"description":1142,"published":1143,"category":712,"image":1144,"draft":716},"\u002Fblog\u002Fvibe-coding-security-scanner","Vibe-Coding-Security-Scanner: was ein URL-Scan übersieht","Ein Vibe-Coding-Security-Scanner liest deine laufende App von außen. Was das abdeckt, die vier Dinge, die er nicht sehen kann, und wie du das Ergebnis liest.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1146,"title":1147,"description":1148,"published":1149,"category":712,"image":1150,"draft":716},"\u002Fblog\u002Fmissing-security-headers","Fehlende Sicherheitsheader: wann sie wirklich zählen","Fehlende Sicherheitsheader ist unser häufigster Befund. Wogegen sie schützen, und wann sie die unwichtigste Zeile in deinem Bericht sind.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1152,"title":1153,"description":1154,"published":1155,"category":712,"image":1156,"draft":716},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Dein OpenAI-API-Schlüssel liegt im Frontend. Tausch ihn aus.","Ein OpenAI-API-Schlüssel im Frontend lässt sich an keine Domain binden. Tausch ihn heute, leg den Aufruf hinter deinen Server und begrenze das Budget.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1158,"title":1159,"description":1160,"published":1161,"category":712,"image":1162,"draft":716},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","API-Schlüssel im Frontend: was 30.998 Apps wirklich ausliefern","Ein API-Schlüssel im Frontend ist meistens ein Google-Maps-Schlüssel. Wir haben 30.998 aktive Vibe-Coding-Apps gescannt und gezählt, was wirklich austritt.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1164,"title":1165,"description":1166,"published":1167,"category":813,"image":1168,"draft":716},"\u002Fblog\u002Fsupabase-backup-tools-compared","Supabase-Backup-Tools im Vergleich, unseres eingeschlossen","Vier Arten von Supabase-Backup-Tool, was jedes wirklich kopiert und wann eine kostenlose GitHub Action jeden Anbieter schlägt, uns eingeschlossen.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1170,"title":1171,"description":1172,"published":1173,"category":712,"image":1174,"draft":716},"\u002Fblog\u002Freplit-secrets-explained","Secrets in Replit nutzen, und was trotzdem veröffentlicht wird","Secrets in Replit nutzen: anlegen, auslesen und die zwei Gründe beheben, warum undefined zurückkommt. Dazu die Schlüssel, die das Werkzeug nicht schützt.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1176,"title":1177,"description":1178,"published":1179,"category":813,"image":1180,"draft":716},"\u002Fblog\u002Fback-up-supabase-free-tier","Supabase Gratis-Tarif: Backup ohne Terminal selbst machen","Im Supabase Gratis-Tarif gibt es keine Backups, die Kopie musst du selbst machen. Wie das im Dashboard geht und was der CSV-Weg auslässt.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1182,"title":1183,"description":1184,"published":1185,"category":712,"image":1186,"draft":716},"\u002Fblog\u002Fis-supabase-secure","Ist Supabase sicher? Ja. Dein Projekt ist eine eigene Frage","Ist Supabase sicher? Die Plattform ist auditiert, verschlüsselt und pentestet. Supabase schreibt selbst auf, wo das aufhört und deine Einstellungen anfangen.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1188,"title":1189,"description":1190,"published":1191,"category":712,"image":1192,"draft":716},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Wo du deine Supabase API-Keys findest: anon, service_role, URL","Projekt-URL, anon-Schlüssel und service_role-Schlüssel liegen auf einer Seite im Dashboard. Wo sie ist, und welcher der vier Werte in deine App gehört.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1194,"title":1195,"description":1196,"published":1197,"category":712,"image":1198,"draft":716},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy in Supabase: was jetzt?","\"New row violates row-level security policy\" heißt, Supabase hat einen Schreibvorgang abgelehnt. Die schnelle Lösung öffnet die Tabelle wieder für alle.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1200,"title":1201,"description":1202,"published":1203,"category":712,"image":1204,"draft":716},"\u002Fblog\u002Fcors-wildcard-security-risk","Ist eine CORS-Wildcard ein Sicherheitsrisiko? Meist nicht.","Ist eine CORS-Wildcard ein Sicherheitsrisiko? Meist ist sie die Voreinstellung deines Builders und gibt nichts preis, was dein Server nicht ohnehin herausgab.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1206,"title":1207,"description":1208,"published":1209,"category":813,"image":1210,"draft":716},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase Branching ist kein Backup. Es geht nur vorwärts.","Warum Supabase Branching kein Backup ist: Ein Branch startet ohne deine Daten, und ein Merge bringt nur das Schema. Wofür es gut ist und was stattdessen hilft.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1212,"title":1213,"description":1214,"published":1215,"category":813,"image":1216,"draft":716},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Supabase-Backup wiederherstellen, und was danach kaputt ist","Wie du ein Supabase-Backup aus dem Dashboard oder aus einer Dump-Datei wiederherstellst, was ersetzt wird und warum die App danach kaputt sein kann.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1218,"title":1219,"description":1220,"published":1221,"category":712,"image":1222,"draft":716},"\u002Fblog\u002Fsupabase-storage-bucket-public","Dein Supabase-Storage-Bucket ist öffentlich. Ist das ein Problem?","Ein öffentlicher Supabase-Storage-Bucket heißt: Wer die URL einer Datei hat, kann sie öffnen. Er heißt nicht, dass jemand den Inhalt auflisten darf.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1224,"title":1225,"description":1226,"published":1227,"category":712,"image":1228,"draft":716},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Ist ein Google-API-Schlüssel im Frontend ein Problem?","Ein Google-API-Schlüssel im Frontend ist der Fund unseres Scanners Nummer eins, und meistens unbedenklich. Eine kostenlose Einstellung entscheidet darüber.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1230,"title":1231,"description":1232,"published":1233,"category":813,"image":1234,"draft":716},"\u002Fblog\u002Fai-agent-deleted-my-database","Ein KI-Agent hat meine Supabase-Daten gelöscht. Was hole ich zurück?","Ein KI-Agent hat Daten aus deiner Datenbank gelöscht. Was du zurückholst, stand schon vorher fest, und die nächsten Minuten entscheiden über den Rest.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1236,"title":1237,"description":1238,"published":1239,"category":712,"image":1240,"draft":716},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Kann jeder deine Supabase-Datenbank lesen? 3.680 Apps im Test","Kann jeder deine Supabase-Datenbank ohne Login lesen? Wir haben 30.998 aktive Apps aus KI-Buildern gescannt und gemessen, wie oft die Antwort ja lautet.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1242,"title":1243,"description":1244,"published":1239,"category":712,"image":1245,"draft":716},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source-Maps öffentlich: deine App veröffentlicht ihren Quellcode","Eine öffentliche Source-Map lässt jeden den Originalcode deiner App lesen, Kommentare inklusive. Der 30-Sekunden-Check, und was wirklich zählt.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1247,"title":1248,"description":1249,"published":1250,"category":712,"image":1251,"draft":716},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: ist er derselbe wie der anon key?","Supabase hat anon und service_role durch öffentliche und geheime Schlüssel ersetzt. Welcher gehört in deine App, und welcher nie?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1253,"title":1254,"description":1255,"published":1256,"category":813,"image":1257,"draft":716},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Sichert Supabase meine Datenbank? Das hängt von deinem Tarif ab.","Sichert Supabase deine Datenbank? Auf bezahlten Tarifen täglich, im Gratis-Tarif gar nicht. So findest du heraus, was du hast und was es nicht abdeckt.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1259,"title":1260,"description":1261,"published":1262,"category":712,"image":1263,"draft":716},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security ist an. Die Tabelle ist trotzdem offen.","Supabase Row Level Security anzuschalten schützt keine Tabelle. Erst deine Policies tun das, und die, die deine App repariert hat, lässt oft alle herein.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1265,"title":1266,"description":1267,"published":1262,"category":813,"image":1268,"draft":716},"\u002Fblog\u002Fversion-history-is-not-a-backup","Der Versionsverlauf ist kein Backup. Er holt keine Tabelle zurück.","Lovable und Bolt führen einen Versionsverlauf für deinen Code. Deine Datenbank ist ein eigener Dienst, und ein Rücksprung holt deine Daten nicht zurück.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1270,"title":1271,"description":1272,"published":1273,"category":813,"image":1274,"draft":716},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Drei Wege, eine Supabase-Datenbank zu sichern, und was fehlt","Das Dashboard, pg_dump und ein verwalteter Dienst. Was jeder Weg wirklich sichert, was er stillschweigend auslässt und welcher den Kontoverlust übersteht.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":179,"title":1276,"description":1277,"published":1273,"category":712,"image":1278,"draft":716},"Welche API-Schlüssel im Frontend sicher sind, und welche nicht","Dein Supabase-anon-Schlüssel darf öffentlich sein. Der service_role-Schlüssel nicht. Er ignoriert jede Regel, die du setzt. So erkennst du den Unterschied.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213638654]