[{"data":1,"prerenderedAt":1193},["ShallowReactive",2],{"blog-es-supabase-auth-redirects-to-localhost":3,"blog-index-es":663},{"id":4,"title":5,"body":6,"category":620,"cover":621,"coverAlt":622,"description":623,"draft":624,"extension":625,"faq":626,"image":642,"keywords":643,"meta":651,"navigation":652,"ogTitle":653,"path":654,"published":655,"seo":656,"stem":657,"tldr":658,"updated":655,"__hash__":662},"blog_es\u002Fblog\u002Fsupabase-auth-redirects-to-localhost.md","Por qué los enlaces de email de Supabase redirigen a localhost:3000",{"type":7,"value":8,"toc":608},"minimark",[9,13,24,31,38,46,51,54,73,79,95,99,102,132,154,166,172,179,183,186,217,221,224,237,240,244,255,280,298,319,339,408,414,418,421,428,441,444,447,483,488,491,498,502,505,514,528,537,557,561,596],[10,11,12],"p",{},"Un usuario nuevo se registra en tu app en vivo, abre el email de confirmación y\npulsa el botón. Su navegador abre una página que dice \"This site can't be\nreached\" y \"localhost refused to connect\" (así en un Chrome en inglés), sobre\nuna dirección que empieza así:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","http:\u002F\u002Flocalhost:3000\u002F#access_token=…&expires_at=…&expires_in=…&refresh_token=…&sb=&token_type=bearer&type=signup\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26,27,30],{},"Si tu app usa el flujo PKCE, termina en ",[21,28,29],{},"?code=…",". Construiste la app con\nLovable, Bolt, v0, Cursor, Claude Code o Replit, en la vista previa iba\nperfecta, y el inicio de sesión con contraseña sigue funcionando.",[10,32,33,34,37],{},"Una redirección de Supabase a localhost significa que Supabase Auth, la parte\nde Supabase que inicia la sesión de la gente, terminó su trabajo y luego envió\na la persona a la Site URL de tu proyecto, que sigue diciendo\n",[21,35,36],{},"http:\u002F\u002Flocalhost:3000",". Esa dirección significa \"este ordenador\". En el\nordenador de tu usuario ahí no hay nada. La solución son dos ajustes en una\npágina del panel de Supabase.",[10,39,40,41,45],{},"Esta es la parte que los arreglos rápidos de internet hacen mal: ",[42,43,44],"strong",{},"el comodín\nque hace desaparecer este mensaje en una línea es también el que deja que el\nenlace de un desconocido envíe a tus usuarios a su página, con la sesión ya\niniciada."," Los ajustes de abajo hacen que los enlaces funcionen y mantienen\nesa puerta cerrada.",[47,48,50],"h2",{"id":49},"qué-significa-una-redirección-de-supabase-a-localhost","¿Qué significa una redirección de Supabase a localhost?",[10,52,53],{},"Significa que Supabase envió a la persona a la dirección por defecto de tu\nproyecto, porque no aceptó una mejor.",[10,55,56,57,64,65,68,69,72],{},"Cada email que Supabase envía por ti, sea una confirmación de registro, un\nmagic link, un restablecimiento de contraseña o una invitación, enlaza primero\na la dirección propia de tu proyecto. La\n",[58,59,63],"a",{"href":60,"rel":61},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fauth-email-templates",[62],"nofollow","guía de plantillas de email","\nde Supabase muestra la forma:\n",[21,66,67],{},"https:\u002F\u002Fproject-ref.supabase.co\u002Fauth\u002Fv1\u002Fverify?token=…&type=email&redirect_to=https:\u002F\u002Fexample.com\u002Fpath",".\nSupabase comprueba ahí el token y luego envía el navegador a lo que indique\n",[21,70,71],{},"redirect_to",".",[10,74,75,76,78],{},"Piensa en ello como un poste indicador en la puerta de Supabase. Cada persona\nque abre un enlace inicia sesión en la puerta y luego sigue, con la llave en la\nmano, por una de las flechas. Las flechas las pones tú. La Site URL es la flecha\nque toman todos cuando ninguna otra encaja, y en un proyecto nuevo señala\n",[21,77,36],{},": el taller donde se construyó la app, que en el\nordenador de cualquier otra persona es una habitación vacía.",[10,80,81,82,87,88,91,92,94],{},"La\n",[58,83,86],{"href":84,"rel":85},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fredirect-urls",[62],"guía de redirecciones","\nde Supabase dice que la Site URL define la redirección por defecto cuando el\ncódigo no indica ningún ",[21,89,90],{},"redirectTo",", te pide que la cambies de\n",[21,93,36],{}," a tu dirección de producción y llama a ese ajuste\ncrítico para las confirmaciones por email y los restablecimientos de\ncontraseña.",[47,96,98],{"id":97},"por-qué-supabase-no-hace-caso-a-la-dirección-que-pidió-mi-app","¿Por qué Supabase no hace caso a la dirección que pidió mi app?",[10,100,101],{},"Porque esa dirección no está en tu lista Redirect URLs, y Supabase recurre a\notra sin avisarte.",[10,103,104,105,108,109,112,113,116,117,108,119,112,122,125,126,131],{},"Tu app puede indicar dónde debe aterrizar la gente. En la biblioteca de\nJavaScript de Supabase eso es ",[21,106,107],{},"emailRedirectTo"," en ",[21,110,111],{},"signUp"," y ",[21,114,115],{},"signInWithOtp",",\ny ",[21,118,90],{},[21,120,121],{},"resetPasswordForEmail",[21,123,124],{},"signInWithOAuth",". Después Supabase\nAuth decide en\n",[58,127,130],{"href":128,"rel":129},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Futilities\u002Frequest.go",[62],"una función corta",",\nen este orden:",[133,134,135,142,148],"ol",{},[136,137,138,141],"li",{},[42,139,140],{},"La dirección que pidió tu app",", si coincide con una entrada de tu lista\nRedirect URLs o está en el mismo dominio que tu Site URL.",[136,143,144,147],{},[42,145,146],{},"La dirección de la página de la que vino la petición",", tal como la\ncomunicó el navegador, con la misma regla.",[136,149,150,153],{},[42,151,152],{},"Si no, la Site URL."," Supabase no da ningún error y la consola de tu app\nno muestra nada.",[10,155,156,157,162,163,165],{},"Toma esa decisión cuando se envía el email, y la dirección elegida entra en el\nenlace. Cuando alguien abre el enlace, Supabase vuelve a comprobar esa dirección\ncon tus ajustes tal como están en ese momento. La propia\n",[58,158,161],{"href":159,"rel":160},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Fwhy-am-i-being-redirected-to-the-wrong-url-when-using-auth-redirectto-option-_vqIeO",[62],"respuesta de solución de problemas","\nde Supabase resume la regla en una frase: para que la opción ",[21,164,90],{},"\nfuncione, tienes que poner la URL exacta en el ajuste Redirect URLs.",[167,168],"diagram",{"alt":169,"caption":170,"src":171},"Un enlace de email llega a un poste indicador con tres flechas. Las dos primeras, la de la dirección que pidió la app y la de la página de la que vino la petición, se comprueban cada una con una lista y quedan tachadas. La tercera flecha, la Site URL, lleva a la persona a un portátil con la pantalla apagada y una cruz roja.","Supabase prueba la dirección que pidió tu app y luego la página de la que vino la petición. Cuando ninguna está en tu lista, decide la Site URL.","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fthree-tries-1600x760.png",[10,173,174,175,72],{},"El mismo ajuste decide adónde devuelve \"Sign in with Google\" a la gente, así\nque un botón de Google que aterriza en localhost tiene la misma causa. Un botón\nde Google que se para antes, en una página que dice \"Unsupported provider:\nprovider is not enabled\", es en cambio\n",[58,176,178],{"href":177},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","un interruptor en Supabase y una lista en Google",[47,180,182],{"id":181},"por-qué-no-lo-viste-antes-del-lanzamiento","Por qué no lo viste antes del lanzamiento",[10,184,185],{},"Porque las dos formas en que lo probaste nunca llegan a la Site URL.",[187,188,189,195,201],"ul",{},[136,190,191,194],{},[42,192,193],{},"El inicio de sesión con contraseña ocurre dentro de la página."," No hay\nenlace de email ni paso por la puerta de Supabase, así que nadie lee el poste.",[136,196,197,200],{},[42,198,199],{},"Si construyes con Cursor o Claude Code y tu servidor de desarrollo estaba\nen marcha en el puerto 3000"," cuando probaste el email, el enlace abrió tu\npropia copia local y pareció funcionar.",[136,202,203,206,207,212,213,216],{},[42,204,205],{},"En el backend integrado de Lovable puede que nunca te pase."," La\n",[58,208,211],{"href":209,"rel":210},"https:\u002F\u002Fdocs.lovable.dev\u002Ffeatures\u002Fauthentication",[62],"documentación de autenticación","\nde Lovable dice que pone la Site URL en tu dirección publicada de\n",[21,214,215],{},"lovable.app"," cuando publicas, y que añade un dominio propio a las redirect\nURLs cuando lo conectas. La misma página dice que las apps que usan tu propio\nproyecto de Supabase no reciben actualizaciones automáticas.",[47,218,220],{"id":219},"está-confirmada-la-cuenta-aunque-la-página-no-cargara","¿Está confirmada la cuenta aunque la página no cargara?",[10,222,223],{},"Sí, en una confirmación de registro. Supabase confirma primero y envía el\nnavegador a otra parte después.",[10,225,226,227,232,233,72],{},"En\n",[58,228,231],{"href":229,"rel":230},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fapi\u002Fverify.go",[62],"el código que procesa el enlace",",\nla cuenta se confirma antes de que salga la redirección. La página que no\ncarga llega cuando el trabajo ya está hecho. Así que dile a la persona que\npuede iniciar sesión en tu sitio en vivo con la contraseña que eligió. Volver a\npulsar el mismo email no sirve: el enlace funciona una vez, y la segunda\npulsación responde\n",[58,234,236],{"href":235},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","\"Email link is invalid or has expired\"",[10,238,239],{},"Un magic link o un restablecimiento de contraseña es distinto. Esa sesión fue\na localhost y se quedó allí, así que cuando hayas corregido los ajustes la\npersona necesita un email nuevo.",[47,241,243],{"id":242},"cómo-arreglar-la-redirección-de-supabase-a-localhost","Cómo arreglar la redirección de Supabase a localhost",[10,245,246,247,250,251,254],{},"Cambia la Site URL y luego añade las demás direcciones a las que envías a la\ngente. Las dos están en la página ",[42,248,249],{},"URL Configuration",", dentro de\n",[42,252,253],{},"Authentication",", en el panel de Supabase.",[10,256,257,264,267,268,270,271,275,276,279],{},[42,258,259,260,263],{},"Pon la Site URL en tu dirección en vivo, con ",[21,261,262],{},"https:\u002F\u002F"," delante.",[21,265,266],{},"https:\u002F\u002Fyourapp.com",", escrita entera. Sin el ",[21,269,262],{},", Supabase la lee como\nuna ruta dentro de su propia dirección, y la persona aterriza en tu proyecto de\nSupabase con ",[58,272,274],{"href":273},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\"",".\nA partir de ahí, cualquier dirección de ese dominio se acepta en cualquier ruta\nsin entrada en la lista, así que ",[21,277,278],{},"https:\u002F\u002Fyourapp.com\u002Fwelcome"," funciona en\ncuanto la Site URL es correcta.",[10,281,282,285,286,289,290,293,294,297],{},[42,283,284],{},"Añade las demás direcciones a Redirect URLs."," La versión con ",[21,287,288],{},"www"," si la\ngente la usa, la dirección publicada en el builder\n(",[21,291,292],{},"https:\u002F\u002Fyourapp.lovable.app",", por ejemplo) si la gente se registra ahí, y\nnada más. Una entrada es un patrón, así que ",[21,295,296],{},"https:\u002F\u002Fyourapp.com\u002F**"," cubre cada\npágina de ese único dominio.",[10,299,300,303,304,307,308,310,311,314,315,318],{},[42,301,302],{},"Comprueba lo que pide tu código."," Si pasa ",[21,305,306],{},"window.location.origin",", la\ndirección es aquella en la que se abrió la página, y cada dirección que eso\npueda producir tiene que estar en el dominio de tu Site URL o en la lista.\nCompáralas letra por letra: con ",[21,309,288],{}," o sin él, con ",[21,312,313],{},"https"," o sin él. Una\nentrada sin ",[21,316,317],{},"\u002F**"," al final coincide con esa dirección exacta y con nada por\ndebajo.",[10,320,321,324,325,328,329,331,332,334,335,338],{},[42,322,323],{},"Revisa tus plantillas de email."," Una plantilla que construye su propio\nenlace con ",[21,326,327],{},"{{ .SiteURL }}"," envía a todo el mundo a la Site URL, pida lo que\npida tu app. La guía de redirecciones de Supabase dice que, al usar la opción\n",[21,330,90],{},", puede que tengas que sustituir ",[21,333,327],{}," por\n",[21,336,337],{},"{{ .RedirectTo }}"," en tus plantillas de email.",[340,341,342,355],"table",{},[343,344,345],"thead",{},[346,347,348,352],"tr",{},[349,350,351],"th",{},"Lo que ves",[349,353,354],{},"Lo que cambias",[356,357,358,370,378,386,397],"tbody",{},[346,359,360,367],{},[361,362,363,364],"td",{},"Todos los enlaces abren ",[21,365,366],{},"localhost:3000",[361,368,369],{},"La Site URL",[346,371,372,375],{},[361,373,374],{},"Los enlaces abren tu Site URL en lugar de la dirección que pidió tu código",[361,376,377],{},"Añade esa dirección a Redirect URLs, letra por letra",[346,379,380,383],{},[361,381,382],{},"El dominio en vivo funciona y la dirección publicada en el builder no",[361,384,385],{},"Añade la dirección publicada a Redirect URLs",[346,387,388,391],{},[361,389,390],{},"Un enlace abre tu dirección de Supabase con \"No API key found in request\"",[361,392,393,394,396],{},"Añade ",[21,395,262],{}," a la Site URL",[346,398,399,402],{},[361,400,401],{},"La dirección que pide tu app está en la lista y el enlace sigue sin hacerle caso",[361,403,404,405,407],{},"El ",[21,406,327],{}," de la plantilla de email",[10,409,410,411,413],{},"Después regístrate otra vez con una dirección que no hayas usado. Un email\nenviado antes del arreglo con el enlace estándar de Supabase, y abierto dentro\nde su hora, aterriza ahora en tu sitio en vivo, porque Supabase vuelve a\ncomprobar la dirección cuando se abre el enlace. Eso vale salvo que\n",[21,412,36],{}," siga en tu lista.",[47,415,417],{"id":416},"qué-redirect-urls-es-seguro-permitir","¿Qué Redirect URLs es seguro permitir?",[10,419,420],{},"Las direcciones exactas que son tuyas. Un comodín es para los despliegues de\nvista previa, y solo limitado a tu propio equipo o proyecto.",[10,422,423,424,427],{},"La guía de redirecciones de Supabase lo dice claro: el \"globstar\" (",[21,425,426],{},"**",") es útil\npara el desarrollo local y las direcciones de vista previa, pero en producción\nrecomienda fijar la ruta de redirección exacta de tu Site URL.",[10,429,430,431,436,437,440],{},"El motivo es lo que viaja con la persona. En el flujo por defecto, Supabase\nescribe la nueva sesión en la dirección a la que la envía:\n",[58,432,435],{"href":433,"rel":434},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Ftokens\u002Fservice.go",[62],"el código que la construye","\nañade ",[21,438,439],{},"#access_token=…&refresh_token=…"," a la dirección de redirección.\nCualquier página que esté en esa dirección puede leer esos dos valores, y con\nellos es ese usuario. En el poste, la flecha decide quién recibe la llave.",[10,442,443],{},"Así que una entrada que coincide con una dirección que controla otra persona es\nuna vía de entrada a las cuentas de tus usuarios. Cualquiera puede pedirle a tu\nproyecto que envíe por email un enlace de inicio de sesión a uno de tus\nusuarios, con la clave pública que está en tu app a propósito, e indicar su\npropia página como destino. El email que llega es de verdad de tu app. El flujo\nPKCE no cambia esto, porque quien escribió ese enlace empezó el inicio de\nsesión, y PKCE entrega la sesión a quien lo empezó.",[10,445,446],{},"Los patrones que coinciden con direcciones que otras personas pueden crear:",[187,448,449,457,468],{},[136,450,451,456],{},[42,452,453,455],{},[21,454,426],{}," solo"," coincide con todas las direcciones que existen.",[136,458,459,464,465,72],{},[42,460,461],{},[21,462,463],{},"https:\u002F\u002F*.vercel.app\u002F**"," coincide con todos los despliegues de Vercel de\ninternet, y cualquiera puede crear uno. El propio ejemplo de Supabase lleva tu\nequipo: ",[21,466,467],{},"https:\u002F\u002F*-\u003Cteam-or-account-slug>.vercel.app\u002F**",[136,469,470,479,480,72],{},[42,471,472,475,476],{},[21,473,474],{},"https:\u002F\u002F*.lovable.app\u002F**",", ",[21,477,478],{},"https:\u002F\u002F*.netlify.app\u002F**"," y la misma forma\nen el dominio de cualquier builder hacen lo mismo para ese builder. El ejemplo\nde Supabase para Netlify también está limitado:\n",[21,481,482],{},"https:\u002F\u002F**--my_org.netlify.app\u002F**",[167,484],{"alt":485,"caption":486,"src":487},"Dos postes indicadores. A la izquierda la lista tiene una dirección exacta, un enlace preparado que señala a otro sitio es rechazado y la persona llega a su propia casa con la llave. A la derecha la lista tiene un comodín, el enlace preparado se acepta y la llave va a otra casa con el contorno rojo.","Una entrada exacta manda a casa un enlace preparado. Un comodín que coincide con las apps de otros deja que les entregue la sesión.","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fwho-gets-the-key-1600x760.png",[10,489,490],{},"Si acabas de arreglar esto pegando un comodín, vuelve a mirar la lista hoy.",[10,492,493,494,72],{},"El lanzamiento es también el momento en que se revisan los demás ajustes que\nsolo importan en producción. Nuestro escaneo gratuito lee tu app en vivo desde\nfuera e informa de lo que un desconocido puede alcanzar: tablas que responden a\ncualquiera, claves secretas en el código que envía tu app, cabeceras que\nfaltan, el certificado. Tarda unos 20 segundos y no necesita cuenta:\n",[58,495,497],{"href":496},"\u002Fsecurity-scanner","escanea tu app",[47,499,501],{"id":500},"vigilar-la-app-en-vivo-después-del-lanzamiento","Vigilar la app en vivo después del lanzamiento",[10,503,504],{},"Este ajuste se corrige una vez. Lo que tu app envía a los visitantes cambia con\ncada despliegue, y esa parte se puede vigilar desde fuera.",[10,506,507],{},[42,508,509,513],{},[58,510,512],{"href":511},"\u002Fwebsite-monitoring","Reeve Monitor"," sigue comprobando tu app en vivo:",[187,515,516,519,522,525],{},[136,517,518],{},"si está disponible, cada 60 segundos, para distinguir \"el enlace no funciona\" de \"el sitio está caído\"",[136,520,521],{},"las nueve comprobaciones cada hora, en hasta tres apps, incluidas las claves secretas en el código que tu app envía a los visitantes",[136,523,524],{},"un mensaje cuando un resultado cambia, para que un problema que sale con un despliegue posterior te llegue sin que tengas que ir a mirar",[136,526,527],{},"un informe mensual, en lenguaje claro, de lo que vio",[10,529,530],{},[42,531,532,536],{},[58,533,535],{"href":534},"\u002Fsupabase-backups","Reeve Care"," guarda una copia de tu base de datos de\nSupabase, con las cuentas incluidas:",[187,538,539,542,545,548,551,554],{},[136,540,541],{},"una copia cifrada según una programación, en el almacenamiento propio de Reeve en la UE, fuera de tu cuenta de Supabase",[136,543,544],{},"el esquema auth en el que viven las cuentas de tus usuarios, para que vuelvan con todo lo demás",[136,546,547],{},"cada copia verificada antes de contar, contando las filas de cada tabla",[136,549,550],{},"también tus archivos subidos, en cuanto conectes una credencial de Storage",[136,552,553],{},"una restauración en un clic, con una copia de seguridad del estado actual tomada antes",[136,555,556],{},"todo lo que hace Monitor",[47,558,560],{"id":559},"qué-hacer-ahora","Qué hacer ahora",[562,563,564],"key-takeaways",{},[187,565,566,572,578,590,593],{},[136,567,568,569,571],{},"Pon la Site URL de la página URL Configuration en tu dirección en vivo, con ",[21,570,262],{}," incluido.",[136,573,574,575,577],{},"Añade a Redirect URLs las demás direcciones exactas a las que envías a la gente, como la versión con ",[21,576,288],{}," y la dirección publicada en el builder.",[136,579,580,581,583,584,586,587,589],{},"Asegúrate de que cada dirección que tu código pasa como ",[21,582,107],{}," o ",[21,585,90],{}," está en la lista, y usa ",[21,588,337],{}," en las plantillas que deban seguirla.",[136,591,592],{},"Di a quien vio la página de localhost después de registrarse que su cuenta está confirmada. Los magic links y los restablecimientos de contraseña necesitan un email nuevo.",[136,594,595],{},"Limita los comodines a las vistas previas de tu equipo, y nunca permitas todas las apps del dominio de un builder.",[10,597,598,599,602,603,607],{},"Si la gente pulsa el enlace nuevo y le dice que ha caducado,\n",[58,600,601],{"href":235},"ese mensaje tiene su propia página",".\nLa ",[58,604,606],{"href":605},"\u002Fchecklist","lista de seguridad de 10 minutos"," cubre lo que suele quedar\nabierto en una app recién lanzada.",{"title":23,"searchDepth":609,"depth":609,"links":610},3,[611,613,614,615,616,617,618,619],{"id":49,"depth":612,"text":50},2,{"id":97,"depth":612,"text":98},{"id":181,"depth":612,"text":182},{"id":219,"depth":612,"text":220},{"id":242,"depth":612,"text":243},{"id":416,"depth":612,"text":417},{"id":500,"depth":612,"text":501},{"id":559,"depth":612,"text":560},"Fundamentos de seguridad","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcover-1200x630.png","Un poste indicador cuya flecha iluminada señala lejos de la casa a la que debería llevar, hacia un portátil con la pantalla apagada.","Si Supabase redirige a localhost:3000, la Site URL nunca se cambió o tu dirección falta en Redirect URLs. La solución, y el comodín que debes evitar.",false,"md",[627,630,633,636,639],{"q":628,"a":629},"¿Por qué mi email de confirmación de Supabase abre localhost:3000?","Porque Supabase envió a la persona a la Site URL de tu proyecto, y la Site URL sigue siendo http:\u002F\u002Flocalhost:3000. Supabase la usa siempre que la dirección que pidió tu app falta en la lista Redirect URLs, o cuando tu app no pidió ninguna. Cámbiala en la página URL Configuration, dentro de Authentication.",{"q":631,"a":632},"¿Está confirmada la cuenta si el enlace abrió localhost?","Sí, en una confirmación de registro. Supabase confirma la dirección primero y envía el navegador a otra parte después, así que la página que falla llega cuando el trabajo ya está hecho. La persona puede iniciar sesión en tu sitio en vivo con la contraseña que eligió. Un magic link o un restablecimiento de contraseña hay que enviarlo de nuevo.",{"q":634,"a":635},"Añadí mi sitio a Redirect URLs y sigue yendo a localhost. ¿Por qué?","La entrada tiene que coincidir con la dirección que se le ofrece a Supabase, letra por letra: con www o sin él, con https o sin él, y la ruta, porque una entrada sin \u002F** al final solo coincide con esa dirección. Si coinciden y el enlace sigue sin hacerle caso, tu plantilla de email construye su enlace con {{ .SiteURL }}. Y corrige la propia Site URL, porque es a la que vuelve todo lo demás.",{"q":637,"a":638},"¿Tengo que añadir mi Site URL a la lista Redirect URLs?","No. Supabase acepta cualquier dirección del propio dominio de la Site URL sin entrada en la lista, en cualquier ruta. La lista es para las demás direcciones: una versión con www, la dirección publicada en el builder, los despliegues de vista previa.",{"q":640,"a":641},"¿Puedo usar un comodín en Redirect URLs de Supabase?","Para vistas previas, limitado a tu propio equipo o proyecto, como en los ejemplos de Supabase. Nunca uno que coincida con direcciones que otras personas pueden crear, como todas las apps de vercel.app o lovable.app. Supabase recomienda la dirección exacta de tu sitio en producción.","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",[644,645,646,647,648,649,650],"supabase redirect to localhost","supabase redirige a localhost","supabase magic link localhost 3000","supabase site url","supabase redirect urls","email de confirmación supabase url incorrecta","supabase redirect url comodín",{},true,"Los enlaces de email de Supabase redirigen a localhost:3000","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","2026-11-02",{"title":5,"description":623},"blog\u002Fsupabase-auth-redirects-to-localhost",[659,660,661],"Una redirección de Supabase a localhost:3000 viene de la Site URL de la página URL Configuration. Un proyecto empieza con http:\u002F\u002Flocalhost:3000, y cada enlace de email vuelve a ella cuando la dirección que pidió tu app no está en la lista Redirect URLs.","Quien pulsó un enlace de registro suele estar ya confirmado. Supabase confirma la cuenta antes de enviarlo a otra parte, así que puede iniciar sesión en tu sitio real.","Pon la Site URL en tu dirección en vivo y añade a la lista las direcciones exactas que usas. Un comodín tan amplio que coincide con la app de otra persona deja que un enlace preparado envíe allí a tus usuarios, con la sesión iniciada.","l9xmVqRkZokXEeJLQBX_WeZDa7LwsjMxj1Cszim75Bg",[664,670,675,681,687,693,699,705,706,711,717,724,730,736,742,748,754,760,766,772,778,784,790,796,802,808,814,820,826,832,838,844,850,856,861,867,873,879,885,891,897,903,909,915,921,927,932,938,944,950,956,962,968,974,980,986,992,998,1004,1010,1016,1022,1028,1034,1040,1046,1052,1058,1064,1070,1076,1082,1088,1094,1100,1106,1112,1118,1124,1130,1136,1142,1148,1154,1159,1165,1171,1177,1182,1188],{"path":665,"title":666,"description":667,"published":668,"category":620,"image":669,"draft":624},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": el pooler no tiene sitio para un cliente más. El puerto de tu cadena de conexión decide el límite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":177,"title":671,"description":672,"published":673,"category":620,"image":674,"draft":624},"Error de Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": Google está desactivado en tu proyecto Supabase. Cómo activarlo y arreglar redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":676,"title":677,"description":678,"published":679,"category":620,"image":680,"draft":624},"\u002Fblog\u002Fviolates-foreign-key-constraint","Error de Supabase \"violates foreign key constraint\" al insertar","Supabase \"insert or update on table violates foreign key constraint\": tu fila apunta a una fila que no existe. Cuál, por qué, y cómo arreglarlo.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":682,"title":683,"description":684,"published":685,"category":620,"image":686,"draft":624},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Error de Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": una columna obligatoria llegó vacía. De dónde vino el null, y cómo arreglarlo.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":688,"title":689,"description":690,"published":691,"category":620,"image":692,"draft":624},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": adónde fue la sesión","\"Auth session missing!\" es supabase-js sin encontrar ninguna sesión iniciada y sin llegar a preguntar a Supabase. Adónde fue la sesión, y el arreglo.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":694,"title":695,"description":696,"published":697,"category":620,"image":698,"draft":624},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": no hay nadie conectado","\"invalid claim: missing sub claim\": Supabase Auth recibió un token auténtico sin ningún usuario, la clave del proyecto en lugar de una sesión.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":700,"title":701,"description":702,"published":703,"category":620,"image":704,"draft":624},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": la causa real","\"Failed to send a request to the Edge Function\": el navegador no recibió una respuesta legible. Su consola dice por qué y si tu función se ejecutó.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":654,"title":5,"description":623,"published":655,"category":620,"image":642,"draft":624},{"path":235,"title":707,"description":708,"published":709,"category":620,"image":710,"draft":624},"Supabase \"Email link is invalid or has expired\" con un enlace nuevo","Con un enlace enviado hace un minuto, \"Email link is invalid or has expired\" en Supabase suele indicar que un filtro de correo lo usó antes. Cómo arreglarlo.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":712,"title":713,"description":714,"published":715,"category":620,"image":716,"draft":624},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\", explicado","Supabase \"canceling statement due to statement timeout\": una consulta superó el límite de su rol, 3 segundos para un visitante. Revisa antes la política RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":718,"title":719,"description":720,"published":721,"category":722,"image":723,"draft":624},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" en Supabase, y qué se va con él","\"Database error deleting user\" en Supabase: tu base de datos rechazó el borrado. La causa está en tus logs y el arreglo decide qué más se borra.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":725,"title":726,"description":727,"published":728,"category":620,"image":729,"draft":624},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" en Supabase","¿Tu webhook de Stripe en una Edge Function de Supabase dice \"No signatures found matching the expected signature\"? Tiene dos causas. Sigue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":731,"title":732,"description":733,"published":734,"category":620,"image":735,"draft":624},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" en Supabase: las tres causas","Supabase dice \"Invalid login credentials\" ante una contraseña errónea, un email desconocido y una cuenta de Google. Cómo saber cuál es.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":737,"title":738,"description":739,"published":740,"category":620,"image":741,"draft":624},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": el error real","\"Edge Function returned a non-2xx status code\" significa que tu función de Supabase respondió con un error. Aquí ves dónde leer el real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":743,"title":744,"description":745,"published":746,"category":620,"image":747,"draft":624},"\u002Fblog\u002Fcertificate-not-trusted","Certificado no confiable: tres causas aparte de la caducidad","¿Certificado no confiable aunque la fecha está bien? Nombra otra dirección, se firmó a sí mismo o a su cadena le falta un eslabón. Cómo saber cuál.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":749,"title":750,"description":751,"published":752,"category":620,"image":753,"draft":624},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": lee las comillas","Supabase \"invalid input syntax for type uuid\" significa que tu app envió algo que no es un id. Lee las comillas, frena la consulta, conserva la columna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":755,"title":756,"description":757,"published":758,"category":620,"image":759,"draft":624},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": el valor ya está ocupado. Encuentra la columna, elige un arreglo y aparta el valor de la pantalla.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":761,"title":762,"description":763,"published":764,"category":620,"image":765,"draft":624},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" aunque la tabla está ahí","Supabase \"relation does not exist\" o PGRST205: ninguna tabla tiene ese nombre en ese esquema. Cuatro comprobaciones, y lo que abre exponer un esquema.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":767,"title":768,"description":769,"published":770,"category":620,"image":771,"draft":624},"\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\" muestra los nombres de argumentos que envió tu app. Compáralos con la función.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":773,"title":774,"description":775,"published":776,"category":620,"image":777,"draft":624},"\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\" suele ser un nombre que no coincide. Cuatro comprobaciones y la línea que recarga.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":779,"title":780,"description":781,"published":782,"category":620,"image":783,"draft":624},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": dos límites, un solo código","Supabase \"Email Rate Limit Exceeded\" limita cada email que envía tu proyecto: 2 por hora con el remitente integrado. Qué cuenta y cómo subirlo.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":785,"title":786,"description":787,"published":788,"category":620,"image":789,"draft":624},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" cierra la sesión de tus usuarios. Tres causas, y cómo las separa el log de Auth.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":791,"title":792,"description":793,"published":794,"category":620,"image":795,"draft":624},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": tres causas","Supabase \"permission denied for schema public\" es un grant que falta en el esquema. Qué lo quitó y la línea que lo devuelve.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":797,"title":798,"description":799,"published":800,"category":620,"image":801,"draft":624},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": las tres cosas que significa","Supabase \"Bucket not found\" es una de tres cosas: un enlace público a un bucket privado, un nombre que no coincide exactamente o el proyecto equivocado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":803,"title":804,"description":805,"published":806,"category":620,"image":807,"draft":624},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: ¿qué clave dejó de funcionar?","Un error Supabase invalid JWT es PGRST301: un token firmado no pasó la verificación. En un proyecto nuevo se trata de la sesión, no de la clave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":809,"title":810,"description":811,"published":812,"category":620,"image":813,"draft":624},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" casi siempre es ninguna","Supabase devuelve PGRST116, \"JSON object requested, multiple (or no) rows returned\", cuando tu consulta no encontró nada. Una fila oculta parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":815,"title":816,"description":817,"published":818,"category":620,"image":819,"draft":624},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" en Supabase: dónde mirar","\"Database error saving new user\" significa que algo unido a tu registro de Supabase falló y se deshizo entero. El error real está en tus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":821,"title":822,"description":823,"published":824,"category":620,"image":825,"draft":624},"\u002Fblog\u002Fwhat-is-supabase","¿Qué es Supabase? La base de datos que eligió tu builder","Qué es Supabase: la base de datos, el login y el almacenamiento de archivos de tu app. Supabase lleva los servidores; las reglas sobre tus filas son tuyas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":827,"title":828,"description":829,"published":830,"category":620,"image":831,"draft":624},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Una clave AWS expuesta en tu frontend no es como una clave OpenAI","Una clave de acceso de AWS expuesta en tu frontend lee y escribe tu almacenamiento. La solución suele ser una presigned URL, no una clave nueva.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":833,"title":834,"description":835,"published":836,"category":620,"image":837,"draft":624},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" al subir","\"New row violates row-level security policy for table objects\" significa que tu subida no tiene regla insert. Hacer público el bucket no añade ninguna.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":839,"title":840,"description":841,"published":842,"category":620,"image":843,"draft":624},"\u002Fblog\u002Fbase44-security-scan","Escaneo de seguridad de Base44: lo que solo él ve","El escaneo de seguridad de Base44 revisa siete tipos de problema desde dentro. Esta es la mitad que lee y nadie más puede leer, y la mitad que nunca mira.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":845,"title":846,"description":847,"published":848,"category":620,"image":849,"draft":624},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Tu clave API se filtró. El orden en el que hay que actuar","Una clave API se filtró y no sabes por dónde empezar. No todas las claves de tu frontend lo son, y el orden importa más que la velocidad.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":851,"title":852,"description":853,"published":854,"category":620,"image":855,"draft":624},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sin desactivar RLS","\"Infinite recursion detected in policy for relation\" significa que tu policy preguntó a la tabla que protege. Así se rompe el círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":273,"title":857,"description":858,"published":859,"category":620,"image":860,"draft":624},"\"No API key found in request\" en Supabase, y el arreglo equivocado","\"No API key found in request\" significa que tu petición llegó a Supabase sin clave. Casi todas las respuestas apuntan a las reglas de tu base de datos.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":862,"title":863,"description":864,"published":865,"category":620,"image":866,"draft":624},"\u002Fblog\u002Fis-base44-safe","¿Es seguro Base44? Lo que vimos en 5.442 apps Base44","¿Es seguro Base44? Pasamos nueve comprobaciones a 5.442 apps Base44 en producción. Casi todas sacaron B por motivos que su dueño nunca eligió.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":868,"title":869,"description":870,"published":871,"category":620,"image":872,"draft":624},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Ocultar una clave API: muévela a una Edge Function de Supabase","Ocultar una clave API significa sacarla del navegador, y una Edge Function de Supabase es el sitio más pequeño donde ponerla. Dos pasos importan más.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":874,"title":875,"description":876,"published":877,"category":620,"image":878,"draft":624},"\u002Fblog\u002Fenv-file-exposed-on-your-server","¿Tu archivo .env está expuesto? Las doce rutas a revisar","¿Tu archivo .env está expuesto en tu propio servidor web? Doce direcciones te lo dicen, y un acierto significa que todo lo que contiene ya es público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":880,"title":881,"description":882,"published":883,"category":620,"image":884,"draft":624},"\u002Fblog\u002Fis-v0-safe","Seguridad de v0: las 1.790 aplicaciones escaneadas sacaron una A","Seguridad de v0, medida en 1.790 aplicaciones v0 en vivo: todas sacaron A. Solo 17 nombraban una base de datos, y eso es casi todo lo que mide la A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":886,"title":887,"description":888,"published":889,"category":620,"image":890,"draft":624},"\u002Fblog\u002Fis-bolt-safe","¿Es seguro Bolt? Lo que vimos en 1.123 aplicaciones Bolt","¿Es seguro Bolt? Pasamos 1.123 aplicaciones Bolt en vivo por nueve comprobaciones. El hosting salió limpio. Los hallazgos eran claves y tablas abiertas dentro.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":892,"title":893,"description":894,"published":895,"category":620,"image":896,"draft":624},"\u002Fblog\u002Fis-supabase-down-or-your-app","¿Supabase está caído o es tu app? Cómo distinguirlo","¿Supabase está caído o es tu app? Un proyecto pausado, una base de datos llena y un fallo tuyo parecen lo mismo. Cuatro comprobaciones los separan.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":898,"title":899,"description":900,"published":901,"category":620,"image":902,"draft":624},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","¿Supabase cifra mis datos? Sí. Esto es lo que detiene","¿Supabase cifra los datos? Sí: AES-256 en reposo, TLS en tránsito, SOC 2 e ISO 27001. Qué cubre cada uno, y la fuga que ninguno de ellos detiene.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":904,"title":905,"description":906,"published":907,"category":620,"image":908,"draft":624},"\u002Fblog\u002Fsupabase-free-plan-limits","¿Cuánto cuesta Supabase? Los límites del plan gratuito","Los límites del plan gratuito de Supabase: 500 MB de base de datos, 5 GB de egress y ningún backup. Qué pasa en cada uno y qué cambia Pro por $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":910,"title":911,"description":912,"published":913,"category":722,"image":914,"draft":624},"\u002Fblog\u002Ftest-your-supabase-backup","Prueba tu backup de Supabase antes del día que lo necesites","Cómo probar tu backup de Supabase: restaurarlo en un proyecto de prueba, contar filas, iniciar sesión y buscar la línea que le falta a un archivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":916,"title":917,"description":918,"published":919,"category":722,"image":920,"draft":624},"\u002Fblog\u002Fsupabase-backup-github-action","Backup gratis de Supabase con una GitHub Action, y la trampa","Un backup de Supabase con GitHub Action es gratis y sirve a muchas apps. El workflow, el connection string correcto y el egress de cada ejecución.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":922,"title":923,"description":924,"published":925,"category":722,"image":926,"draft":624},"\u002Fblog\u002Fdownload-your-supabase-backup","Por qué no puedes descargar tu backup de Supabase","No puedes descargar tu backup de Supabase en un proyecto actual: la copia diaria es una instantánea física. Cómo comprobarlo y tener tu propia copia.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":928,"title":929,"description":930,"published":925,"category":620,"image":931,"draft":624},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": el grant que falta","Desde el 30 de octubre, una tabla nueva de Supabase responde \"permission denied for table\" hasta que le das acceso. El grant del email es la mitad del arreglo.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":933,"title":934,"description":935,"published":936,"category":620,"image":937,"draft":624},"\u002Fblog\u002Fopen-api-endpoint-exposed","¿Un endpoint de API abierto es un problema? Mira el JSON","Tu escaneo señaló un endpoint de API abierto. Que importe depende de lo que devolvió, y la mayoría de los que encontramos eran de la plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":939,"title":940,"description":941,"published":942,"category":620,"image":943,"draft":624},"\u002Fblog\u002Flovable-security-scan","Escaneo de seguridad de Lovable: lo que no puede probar","Escaneo de seguridad de Lovable: qué revisan el Quick scan y el Deep scan, cuándo corre cada uno, y lo único que ningún escaneo desde dentro puede probar.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":945,"title":946,"description":947,"published":948,"category":722,"image":949,"draft":624},"\u002Fblog\u002Fsupabase-backup-auth-users","Por qué tu dump de Supabase no tiene usuarios dentro","Ejecuta supabase db dump por sí solo y obtienes la forma de tu base de datos y ninguna de sus filas, sin el esquema auth donde viven tus usuarios.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":951,"title":952,"description":953,"published":954,"category":620,"image":955,"draft":624},"\u002Fblog\u002Fdomain-and-certificate-expiry","Dominio caducado, web caída: qué pasa a partir de ahora","Tu dominio caducó y tu web está caída. Aquí tienes el reloj que acaba de arrancar, por qué el certificado es el menor problema, y cómo comprobar ambos.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":957,"title":958,"description":959,"published":960,"category":620,"image":961,"draft":624},"\u002Fblog\u002Fis-lovable-safe","¿Es seguro Lovable? Lo que vimos en 18.554 aplicaciones Lovable","¿Es seguro Lovable? Pasamos 18.554 aplicaciones Lovable por nueve comprobaciones. La plataforma fue la más limpia de cinco. Los hallazgos estaban dentro.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":963,"title":964,"description":965,"published":966,"category":620,"image":967,"draft":624},"\u002Fblog\u002Fvibe-coded-app-security-checklist","La lista de seguridad del vibe coding, en nueve comprobaciones","Una lista de seguridad del vibe coding con nueve puntos, cada uno verificable en tu app desde fuera por cualquiera, y cada uno con una prueba de una línea.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":969,"title":970,"description":971,"published":972,"category":620,"image":973,"draft":624},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Una clave secreta de Stripe en tu frontend puede mover dinero","Una clave secreta de Stripe expuesta en tu frontend puede reembolsar, cobrar y leer cada ficha de cliente que tienes. Tu clave pk_live_ sí debe estar ahí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":975,"title":976,"description":977,"published":978,"category":620,"image":979,"draft":624},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variables de entorno de Vite expuestas: el prefijo dice publica esto","Variables de entorno de Vite expuestas en tu app: hicieron lo que pedía el prefijo. VITE_ y NEXT_PUBLIC_ significan publica esto, y la IA nunca supo el coste.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":981,"title":982,"description":983,"published":984,"category":620,"image":985,"draft":624},"\u002Fblog\u002Fbase44-source-maps","Seguridad en Base44: qué marca un escaneo y qué te toca arreglar a ti","Seguridad en Base44 en 5.438 apps escaneadas: tres hallazgos en casi todas son de la plataforma, el source map es la insignia de Base44 y lo tuyo es poco.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":987,"title":988,"description":989,"published":990,"category":620,"image":991,"draft":624},"\u002Fblog\u002Fis-cursor-ai-safe","¿Es seguro Cursor AI? El editor, el código y la app que publicaste","¿Es seguro Cursor AI? Tres preguntas en una búsqueda: qué guarda Cursor, en qué falla el código que escribe y si la app que publicaste está abierta.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":993,"title":994,"description":995,"published":996,"category":620,"image":997,"draft":624},"\u002Fblog\u002Fis-replit-safe","¿Es seguro Replit? Lo que vimos en 3.042 aplicaciones Replit en vivo","¿Es seguro Replit? Pasamos 3.042 aplicaciones Replit en vivo por nueve comprobaciones externas. Los hallazgos estaban en la aplicación publicada, no en el host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":999,"title":1000,"description":1001,"published":1002,"category":722,"image":1003,"draft":624},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: tu copia de la base no tiene archivos","Un Supabase storage backup es una tarea aparte. Las copias de la base guardan la lista de tus archivos y ninguno de ellos, así que cada upload queda roto.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1005,"title":1006,"description":1007,"published":1008,"category":722,"image":1009,"draft":624},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery de Supabase: precio y límites","El point-in-time recovery de Supabase rebobina tu base de datos a cualquier segundo de la última semana. Cuesta $100 al mes sobre Pro y solo cubre la base.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1011,"title":1012,"description":1013,"published":1014,"category":722,"image":1015,"draft":624},"\u002Fblog\u002Fsupabase-project-paused-recover","¿Proyecto de Supabase pausado? Tus datos siguen ahí","Supabase pausó tu proyecto tras una semana sin actividad. No se ha borrado nada, Restaurar está junto al nombre y tienes un año antes de que eso cambie.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1017,"title":1018,"description":1019,"published":1020,"category":620,"image":1021,"draft":624},"\u002Fblog\u002Fsafest-ai-app-builder","¿Qué builder de apps con IA es más seguro? 30.998 apps escaneadas","¿Qué builder de apps con IA es más seguro? Escaneamos 30.998 apps activas de Lovable, Base44, Replit, v0 y Bolt. El builder no es lo que decide tu nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":1023,"title":1024,"description":1025,"published":1026,"category":620,"image":1027,"draft":624},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Activa Row Level Security en cada tabla de Supabase y compruébalo","Activar Row Level Security en Supabase sin política cierra la tabla del todo. Una política sin el interruptor no hace nada. Aquí tienes el SQL y la prueba.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":1029,"title":1030,"description":1031,"published":1032,"category":620,"image":1033,"draft":624},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": lo que el aviso no ve","Supabase marca \"RLS disabled in public\" como error. No dice nada de la política de lectura que deja tu tabla igual de abierta a cualquiera.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1035,"title":1036,"description":1037,"published":1038,"category":620,"image":1039,"draft":624},"\u002Fblog\u002Frotate-supabase-service-role-key","Cómo rotar una clave service_role de Supabase filtrada","Supabase dice que primero cierres la fuga. Otras guías dicen que rotes ya. Cuál es lo correcto depende de dónde se filtró tu clave service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1041,"title":1042,"description":1043,"published":1044,"category":620,"image":1045,"draft":624},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Escáneres de seguridad vibe coding comparados, el nuestro incluido","El mejor escáner de seguridad para vibe coding depende de tres preguntas que ninguna lista de funciones responde. Ocho herramientas, con precios.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1047,"title":1048,"description":1049,"published":1050,"category":620,"image":1051,"draft":624},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: haz tú mismo las cinco comprobaciones","Un Supabase security checker lee tu app publicada en lugar de la configuración de tu proyecto. Estas son las cinco comprobaciones y cómo hacer cada una.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1053,"title":1054,"description":1055,"published":1056,"category":620,"image":1057,"draft":624},"\u002Fblog\u002Fvibe-coding-security-scanner","Escáner de seguridad para vibe coding: qué se le escapa","Un escáner de seguridad para vibe coding lee tu app en vivo desde fuera. Qué cubre eso, las cuatro cosas que no puede ver y cómo leer el resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1059,"title":1060,"description":1061,"published":1062,"category":620,"image":1063,"draft":624},"\u002Fblog\u002Fmissing-security-headers","Faltan cabeceras de seguridad: cuándo importa de verdad","Que falten cabeceras de seguridad es el hallazgo que más imprime nuestro escáner. Contra qué protegen y cuándo son la línea menos urgente de tu informe.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1065,"title":1066,"description":1067,"published":1068,"category":620,"image":1069,"draft":624},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Tu clave de API de OpenAI está expuesta en tu frontend. Rótala.","Una clave de API de OpenAI expuesta en tu frontend no se puede atar a un dominio. Rótala hoy, mueve la llamada a tu servidor y limita el gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1071,"title":1072,"description":1073,"published":1074,"category":620,"image":1075,"draft":624},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Clave de API expuesta en el frontend: qué llevan 30.998 apps","Una clave de API expuesta en tu frontend suele ser una clave de Google Maps. Escaneamos 30.998 apps vibe-coded y contamos qué secretos se filtran de verdad.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1077,"title":1078,"description":1079,"published":1080,"category":722,"image":1081,"draft":624},"\u002Fblog\u002Fsupabase-backup-tools-compared","Herramientas de backup de Supabase comparadas, la nuestra incluida","Cuatro tipos de herramienta de backup de Supabase, qué copia cada una y cuándo una GitHub Action gratuita le gana a pagar a cualquiera, nosotros incluidos.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1083,"title":1084,"description":1085,"published":1086,"category":620,"image":1087,"draft":624},"\u002Fblog\u002Freplit-secrets-explained","Cómo usar secrets en Replit, y qué se publica de todos modos","Cómo usar secrets en Replit: añadir uno, leerlo y arreglar las dos causas del undefined. Y las claves que la herramienta Secrets no puede mantener privadas.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1089,"title":1090,"description":1091,"published":1092,"category":722,"image":1093,"draft":624},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups del plan gratuito de Supabase: cómo hacer uno sin terminal","No hay backups en el plan gratuito de Supabase: la copia tienes que hacerla tú. Cómo sacarla desde el panel y qué deja fuera la vía CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1095,"title":1096,"description":1097,"published":1098,"category":620,"image":1099,"draft":624},"\u002Fblog\u002Fis-supabase-secure","¿Supabase es seguro? Sí. Tu proyecto es otra pregunta","¿Supabase es seguro? La plataforma está auditada, cifrada y sometida a pentests. Su propia documentación dice dónde termina eso y empiezan tus ajustes.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1101,"title":1102,"description":1103,"published":1104,"category":620,"image":1105,"draft":624},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Dónde están tus claves API de Supabase: anon, service_role y URL","La URL del proyecto, la clave anon y la clave service_role están en una sola página del panel. Aquí tienes dónde está, y cuál de los cuatro va en tu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1107,"title":1108,"description":1109,"published":1110,"category":620,"image":1111,"draft":624},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy en Supabase. ¿Y ahora?","\"New row violates row-level security policy\" significa que Supabase rechazó una escritura. El arreglo rápido vuelve a abrir la tabla para cualquiera.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1113,"title":1114,"description":1115,"published":1116,"category":620,"image":1117,"draft":624},"\u002Fblog\u002Fcors-wildcard-security-risk","¿Es un comodín CORS un riesgo de seguridad? Casi nunca.","¿Es un comodín CORS un riesgo de seguridad? Casi siempre es el ajuste por defecto de tu builder y no entrega nada que tu servidor no diera ya a cualquiera.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1119,"title":1120,"description":1121,"published":1122,"category":722,"image":1123,"draft":624},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase branching no es un backup. Solo va hacia adelante.","Por qué el branching de Supabase no es un backup: una rama arranca sin tus datos y un merge solo mueve el esquema. Para qué sirve y qué usar en su lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1125,"title":1126,"description":1127,"published":1128,"category":722,"image":1129,"draft":624},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Cómo restaurar un backup de Supabase, y qué se rompe después","Cómo restaurar un backup de Supabase desde el panel o desde un archivo de volcado, qué reemplaza la restauración y por qué tu app puede seguir rota al terminar.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1131,"title":1132,"description":1133,"published":1134,"category":620,"image":1135,"draft":624},"\u002Fblog\u002Fsupabase-storage-bucket-public","Tu bucket de Supabase Storage es público. ¿Es un problema?","Un bucket público de Supabase Storage significa que quien tenga la URL de un archivo puede abrirlo. No significa que alguien pueda listar lo que hay dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1137,"title":1138,"description":1139,"published":1140,"category":620,"image":1141,"draft":624},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","¿Es un problema una clave de API de Google en tu frontend?","Una clave de API de Google en tu frontend es la clave que más encuentra nuestro escáner, y casi siempre no pasa nada. Un ajuste gratuito decide cuál es cuál.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1143,"title":1144,"description":1145,"published":1146,"category":722,"image":1147,"draft":624},"\u002Fblog\u002Fai-agent-deleted-my-database","Un agente de IA borró mis datos de Supabase. ¿Qué puedo recuperar?","Un agente de IA borró datos de tu base. Lo que puedes recuperar ya estaba decidido antes de que se ejecutara, y los próximos minutos deciden el resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1149,"title":1150,"description":1151,"published":1152,"category":620,"image":1153,"draft":624},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","¿Puede cualquiera leer tu base de datos Supabase? 3.680 apps","¿Puede cualquiera leer tu base de datos Supabase sin iniciar sesión? Escaneamos 30.998 apps activas hechas con builders de IA y medimos cuántas dicen que sí.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1155,"title":1156,"description":1157,"published":1152,"category":620,"image":1158,"draft":624},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expuestos: tu app está publicando su código original","Un source map expuesto deja que cualquiera lea el código original de tu app, comentarios incluidos. La comprobación de 30 segundos y lo que de verdad importa.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1160,"title":1161,"description":1162,"published":1163,"category":620,"image":1164,"draft":624},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: ¿es la misma que la anon key?","Supabase sustituyó anon y service_role por claves publicables y secretas. ¿Cuál pertenece a tu app y cuál no debe estar nunca?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1166,"title":1167,"description":1168,"published":1169,"category":722,"image":1170,"draft":624},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","¿Supabase respalda mi base de datos? Depende de tu plan.","¿Supabase respalda tu base de datos? A diario en los planes de pago, y nada en el gratuito. Cómo saber cuál tienes y qué es lo que esa copia no cubre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1172,"title":1173,"description":1174,"published":1175,"category":620,"image":1176,"draft":624},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security está activado. Tu tabla sigue pública.","Activar Supabase Row Level Security no protege una tabla. Lo hacen tus políticas, y la que arregló tu app rota puede dejar entrar a cualquiera.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1178,"title":1179,"description":1180,"published":1175,"category":722,"image":1181,"draft":624},"\u002Fblog\u002Fversion-history-is-not-a-backup","El historial de versiones no es un backup. No recupera una tabla.","Lovable y Bolt guardan un historial de versiones de tu código. Tu base de datos es un servicio aparte, y volver atrás no te devuelve tus datos.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1183,"title":1184,"description":1185,"published":1186,"category":722,"image":1187,"draft":624},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Tres formas de respaldar una base Supabase, y qué falta en cada una","El panel, pg_dump y un servicio gestionado. Qué guarda de verdad cada uno, qué deja fuera sin avisar y cuál sobrevive a perder la cuenta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1189,"title":1190,"description":1191,"published":1186,"category":620,"image":1192,"draft":624},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Qué claves de API son seguras en el navegador y cuáles no","Tu clave anon de Supabase está pensada para ser pública. Tu clave service_role no, y se salta todas las reglas que pongas. Cómo distinguirlas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213644917]