Desarrollo

Cómo solucionar errores de CORS

“Blocked by CORS policy” no es un fallo de tu código, sino una protección del navegador para tus usuarios. La solución siempre está en el servidor que recibe la petición. Esta guía explica qué comprueba el navegador y ofrece configuraciones que funcionan en los casos más comunes.

Intermedio · 9 min de lectura · Actualizada el 30 de octubre de 2026

Cómo solucionar errores de CORS

Qué es CORS realmente

El navegador bloquea que el JavaScript de https://app.example.com lea respuestas de otro origen (esquema + host + puerto), como https://api.example.com, a menos que ese servidor lo permita. El servidor lo indica con headers de respuesta Access-Control-Allow-*. Las peticiones desde curl, Postman o tu backend no se ven afectadas, por eso “funciona en Postman” pero falla en el navegador.

Lee el mensaje de error

  • “No ‘Access-Control-Allow-Origin’ header is present”: el servidor no envió headers de CORS, o devolvió una página de error (404, 500) sin ellos.
  • “Response to preflight request doesn’t pass access control check”: la petición OPTIONS falló. No se gestionó, devolvió un error o no incluía los headers necesarios.
  • “The value of the ‘Access-Control-Allow-Origin’ header must not be the wildcard ‘*’ when credentials mode is ‘include’”: envías cookies, así que el servidor debe devolver el origen exacto.

Revisa la petición fallida en DevTools → Network, o comprueba los headers reales de la respuesta con el HTTP Header Checker.

Peticiones simples y preflight

Una petición es “simple” si es un GET, HEAD o POST con solo headers básicos y un cuerpo de formulario o texto plano. Cualquier otra cosa, como Content-Type: application/json, un header Authorization, PUT o DELETE, hace que el navegador envíe primero una petición OPTIONS de preflight. Tu servidor debe responder con estado 204 o 200 y estos headers:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 600

Configuraciones que funcionan

Express con el paquete cors:

const cors = require('cors');
app.use(cors({
  origin: ['https://app.example.com'],
  credentials: true,                 // only if you send cookies
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));

Nginx:

location /api/ {
  if ($request_method = OPTIONS) {
    add_header Access-Control-Allow-Origin "https://app.example.com" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
    add_header Access-Control-Max-Age 600;
    return 204;
  }
  add_header Access-Control-Allow-Origin "https://app.example.com" always;
  proxy_pass http://backend;
}

El flag always es importante: sin él, Nginx elimina el header en las respuestas de error y el navegador muestra un error de CORS en lugar del 500 real. Genera headers para otros servidores (Vercel, Netlify, Cloudflare Workers, Apache) con el CORS Header Generator.

Cookies y credenciales

Para enviar cookies entre orígenes, la petición necesita credentials: 'include' (fetch) y el servidor debe responder con Access-Control-Allow-Credentials: true y el origen exacto, nunca *. La cookie también necesita SameSite=None; Secure. Si devuelves el origen desde una lista, envía además Vary: Origin para que las cachés no sirvan los headers de un sitio a otro.

Lo que no debes hacer

  • No devuelvas cualquier header Origin con credenciales activadas: así cualquier sitio web podría leer los datos de tus usuarios.
  • No “arregles” CORS con una extensión del navegador ni con un proxy público; solo oculta el problema en tu máquina.
  • Si la API es tuya y está en el mismo sitio, un reverse proxy (mismo origen) elimina CORS por completo.

Reproduce la petición del navegador con el API Tester, o conviértela en código con cURL to Code.

Preguntas frecuentes

¿Puedo solucionar CORS en el frontend?
No. El navegador aplica CORS según los headers de respuesta del servidor. Cambia el servidor o enruta la petición a través de tu propio backend o de un proxy del mismo origen.
¿Por qué funciona en Postman pero no en el navegador?
Postman, curl y los servidores no aplican CORS; solo lo hacen los navegadores, para proteger los datos de los usuarios en otros sitios.
¿Es seguro Access-Control-Allow-Origin: *?
Para APIs públicas de solo lectura y sin cookies, sí. No puede usarse con credenciales, y las APIs privadas deberían listar sus orígenes permitidos.

Sigue leyendo