¿Es seguro dejar la clave anon de Supabase en el frontend?
Por qué la clave anon o publishable de Supabase puede ser pública, qué deja ver cuando falta RLS y cómo revisar tu propio proyecto en diez minutos.
Read in English →
Sí: la clave anon de Supabase (que ahora se llama publishable key y empieza con sb_publishable_) está pensada para ir en el código del navegador, y cualquiera puede verla. Es segura solo porque Row Level Security (RLS) decide qué puede leer y modificar quien la use. Si una tabla de un esquema expuesto tiene RLS apagado, o una política que dice "permitir a todos", esa clave pública le da ese acceso a cualquier persona en internet.
En esta guía verás qué es realmente la clave, hasta dónde llega, las cuatro formas más comunes en que una app hecha con IA filtra datos a través de ella y una prueba corta que puedes hacer hoy mismo en tu proyecto.
¿Qué es la clave anon (o publishable)?
Cada proyecto de Supabase tiene dos tipos de claves. Según la documentación de API keys de Supabase:
| Clave | Formato | Para qué es | ¿Respeta RLS? |
|---|---|---|---|
| Publishable | sb_publishable_... | Navegador, apps móviles, todo lo público | Sí |
| Secret | sb_secret_... | Solo servidores y Edge Functions | No, se salta RLS |
anon (heredada) | JWT largo que empieza con eyJ | Lo mismo que publishable | Sí |
service_role (heredada) | JWT largo que empieza con eyJ | Lo mismo que secret | No |
La clave publishable identifica tu proyecto; no es una contraseña. Supabase anunció que dejará de admitir las claves heredadas anon y service_role hacia finales de 2026. Si tu proyecto de Lovable, Bolt o Cursor todavía usa una clave larga eyJ..., conviene planear el cambio.
Cuando alguien entra sin iniciar sesión, las peticiones con la clave publishable se ejecutan con el rol de Postgres anon. Cuando inicia sesión, la misma clave más su token de sesión se ejecutan como authenticated. Tus políticas deciden qué puede hacer cada rol, fila por fila.
Entonces, ¿cuándo se vuelve peligrosa?
La clave en sí, nunca. Lo peligroso es una base de datos que confía en ella. Estas son las cuatro situaciones típicas en apps generadas con herramientas de IA.
1. Una tabla sin RLS
Si una tabla del esquema public tiene RLS desactivado y conserva los permisos habituales, cualquiera con tu clave publishable puede leer, y muchas veces escribir, todas sus filas a través de la API REST. Es común que la IA cree una tabla nueva en un prompt posterior, después de la primera ronda de seguridad, y que esa tabla se quede sin RLS.
2. Una política que lo permite todo
Políticas como using (true) para select, o un insert con with check (true), parecen resolver el problema porque desaparece el error de permisos. También eliminan la protección. Un true para lectura está bien en contenido realmente público, como artículos publicados. No está bien en pedidos, mensajes o perfiles con correos.
3. Vistas y funciones que se saltan RLS
En Postgres, una vista se ejecuta por defecto con los permisos de su dueño, que en Supabase suele ser un rol que se salta RLS. Si creas una vista sobre una tabla protegida, puede filtrar filas a menos que la crees con security_invoker = true:
create view public.mis_pedidos
with (security_invoker = true)
as select id, total, created_at from public.pedidos;
Algo parecido pasa con las funciones marcadas como security definer en un esquema expuesto: cualquiera puede llamarlas por RPC y se ejecutan con los permisos de su dueño. La guía de RLS de Supabase recomienda no crear funciones security definer en esquemas expuestos.
4. Buckets de Storage públicos
Un bucket público entrega archivos a cualquiera que tenga la URL, sin clave. Eso sirve para logos y fotos de productos, no para facturas o documentos de identidad. Lo explicamos en buckets públicos y privados en Supabase.
¿Cómo reviso si mi clave está exponiendo datos?
No necesitas leer el código para tener una primera respuesta. Hazlo solo con tus propios datos o un proyecto de prueba.
- Abre el Security Advisor en el panel de Supabase. Marca tablas sin RLS en esquemas expuestos y algunas funciones riesgosas. Corrige primero todo lo que aparezca como error.
Revisa el estado de RLS de cada tabla. En el editor SQL:
select tablename, rowsecurity from pg_tables where schemaname = 'public' order by tablename;Todas las filas deberían decir
true.Intenta leer una tabla como visitante anónimo. Copia la URL del proyecto y la clave publishable del diálogo Connect y ejecuta:
curl "https://TU-PROYECTO.supabase.co/rest/v1/profiles?select=*" \ -H "apikey: sb_publishable_xxx"Si recibes filas que no querías publicar, esa tabla necesita una política correcta. Un arreglo vacío
[]suele significar que RLS está activo y ninguna política deja leer aanon.- Repite la prueba con una sesión iniciada, pero de un usuario que no debería ver esos datos (una segunda cuenta de prueba). Muchas filtraciones solo aparecen con usuarios logueados, porque la política dice "cualquier usuario autenticado" en lugar de "el dueño de la fila".
- Lee cada política que contenga
truey decide si esa tabla de verdad es pública.
¿Qué cambia con los nuevos permisos de la Data API?
Supabase también está cambiando lo que exponen las tablas nuevas. Desde el 30 de mayo de 2026, los proyectos nuevos ya no dan acceso automático a los roles anon y authenticated sobre las tablas nuevas de public, y según el changelog de Supabase el mismo comportamiento llega a los proyectos existentes el 30 de octubre de 2026. Las tablas que ya existen conservan sus permisos.
En la práctica, una tabla creada después de esa fecha responde permission denied for table ... (código 42501) por la API hasta que alguien ejecute un grant explícito. Es más seguro, pero invita a pegar un permiso amplio y seguir de largo. El grant abre la puerta de la tabla; RLS sigue decidiendo qué filas pasan. Necesitas las dos cosas.
¿Para qué se usa entonces la clave secret?
Para todo lo que debe saltarse RLS a propósito: un webhook de Stripe que marca un pedido como pagado, una tarea nocturna, un script de administración. Eso corre en un servidor o en una Edge Function, nunca en el navegador. Supabase bloquea las claves secret en navegadores según el User-Agent de la petición, pero eso no protege una clave filtrada que se use desde un script. Si crees que una clave secret llegó al frontend, trátala como filtrada y sigue qué hacer si se filtró la service_role key.
Una regla rápida para variables de entorno: todo lo que empieza con VITE_, NEXT_PUBLIC_ o EXPO_PUBLIC_ termina en el código que descarga el visitante. La clave publishable puede ir ahí. La secret, nunca.
Respuestas rápidas
¿Debo esconder la clave anon en una variable de entorno? Puedes guardarla ahí por orden, pero igual se verá en el navegador. Esconderla no es una medida de seguridad; RLS sí lo es.
¿La clave publishable es más segura que la anon de siempre? Tiene el mismo nivel de acceso. Sus ventajas son que se rota con más facilidad y que no es un JWT de larga duración. Tus políticas importan igual.
¿Alguien puede borrar mis datos con la clave anon? Solo si una política permite delete (o update) a ese rol, o si la tabla no tiene RLS. Con políticas correctas, no.
¿Activar RLS rompe mi app? Puede pasar por un momento: con RLS activo y sin políticas, no se devuelve nada. Agrega una política por cada cosa que la app necesita de verdad. Nuestros ejemplos de políticas RLS cubren los casos comunes.
¿Quieres que alguien más lo revise?
La revisión gratuita de tu app muestra lo que se ve desde afuera, incluidas las claves que viajan en el código. Si prefieres que alguien revise cada tabla, vista, función y bucket, nuestra revisión de seguridad de Supabase hace justamente eso, y el checklist de seguridad para apps hechas con IA te sirve para empezar por tu cuenta. Puedes escribirnos desde contacto.


