Iniciaste sesión sin problemas, pero la pantalla muestra pedidos, perfiles o notas de otros usuarios mezclados con los tuyos. Esto es una fuga de datos, así que es el error más prioritario que hay que arreglar. La causa casi siempre es la misma: el servidor no filtra por "de quién es esta fila" y envía todo al navegador.
Does this match your symptom?
- Tienes la sesión iniciada en tu propia cuenta, pero la lista contiene datos de otras personas
- Al cambiar el
idnumérico en la URL se abre la página de detalle de otra persona - Al principio iba bien, pero al tener más usuarios podían ver los datos de los demás
Why it happens
Tres causas habituales para quienes no son desarrolladores:
- El RLS (Row Level Security) de Supabase está desactivado — las tablas del esquema
publicse pueden leer por completo a través de la API salvo que se active el RLS. - La consulta no tiene la condición "solo lo mío" — falta un
WHERE user_id = ..., o las reglas de Firebase quedaron en modo de prueba (if true). - Filtrar solo en React (lado del cliente) — todas las filas, incluidas las de otras personas, ya llegaron al navegador y solo las ocultaste en pantalla. Abre la pestaña Network de las DevTools y ahí están todas. This is not security.
30-second diagnosis
En el navegador: F12 → pestaña Network → haz clic en la petición que carga la lista → Response.
Si la respuesta JSON contiene filas de otros usuarios, el servidor las está enviando, así que tienes que arreglarlo en el servidor (más abajo). Editar solo React no lo soluciona.
Fix A — If you use Supabase
- Asegúrate de que la tabla tenga una columna
user_id(si falta, añade una columnauuidque guarde el id deauth.users). - Ejecuta esto en el SQL Editor del panel (reemplaza
todospor el nombre de tu tabla):
-- 1) Turn RLS on
alter table todos enable row level security;
-- 2) Auto-fill the owner id on new rows (optional)
alter table todos alter column user_id set default auth.uid();
-- 3) Read only my rows
create policy "select own rows" on todos
for select to authenticated
using ( auth.uid() = user_id );
-- 4) Insert only as myself
create policy "insert own rows" on todos
for insert to authenticated
with check ( auth.uid() = user_id );
-- 5) Update only my rows
create policy "update own rows" on todos
for update to authenticated
using ( auth.uid() = user_id )
with check ( auth.uid() = user_id );
-- 6) Delete only my rows
create policy "delete own rows" on todos
for delete to authenticated
using ( auth.uid() = user_id );
- Guarda, inicia sesión con otra cuenta y vuelve a probar. Ahora las filas de otros usuarios desaparecen por completo de la respuesta.
> Nota: una vez activado el RLS, no se ve nada hasta que añadas políticas — es lo esperado. Las políticas de arriba son las que restauran el "solo lo mío".
Fix B — If you use Firebase (Firestore)
En la consola de Firebase ve a Firestore Database → Rules, reemplaza la regla de modo de prueba (allow read, write: if true;) por la regla de propietario y pulsa Publish:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /todos/{docId} {
allow read, update, delete: if request.auth != null
&& request.auth.uid == resource.data.uid;
allow create: if request.auth != null
&& request.auth.uid == request.resource.data.uid;
}
}
}
También debes filtrar la consulta a tus propios datos. Las reglas de Firestore no son filtros: una consulta demasiado amplia no se recorta en silencio, se rechaza directamente.
import { collection, query, where, getDocs } from "firebase/firestore";
const q = query(
collection(db, "todos"),
where("uid", "==", auth.currentUser.uid) // only mine
);
const snap = await getDocs(q);
(Si tus datos están indexados por el id de usuario en la ruta del documento, usa match /users/{userId} con allow read, write: if request.auth.uid == userId;.)
Fix C — If you have your own backend (Express, etc.)
Fuerza la consulta con el userId tomado de la sesión/token de inicio de sesión. Never trust an id sent by the client — se puede cambiar.
// use the value from the session only
const rows = await db.query(
"select * from todos where user_id = $1",
[req.user.id] // NOT req.body / req.query id
);
The one line to remember
Un filtro del lado del cliente (React) sirve para ordenar la pantalla, no para la seguridad. Solo el servidor (RLS, reglas de seguridad, WHERE) detiene realmente la fuga.
