---
term: 'CORS (Cross-Origin Resource Sharing)'
seoTitle: '¿Qué es CORS? Errores, preflight y correcciones'
headline: '¿Qué es CORS (Cross-Origin Resource Sharing)?'
slug: cors
category: api-realtime
shortDefinition: 'CORS es un mecanismo del navegador que permite al servidor declarar qué otros origins pueden llamarlo, relajando a propósito la política de same-origin.'
relatedTerms:
  - api-key-security
  - api-gateway-architecture
  - cross-site-scripting-xss-prevention
contrastsWith:
  - cross-site-scripting-xss-prevention
faq:
  - question: '¿Qué es CORS en términos simples?'
    answer: 'El sistema de permisos del navegador para llamadas de API entre sitios. Por defecto, los scripts de un origin no pueden leer respuestas de otro — la política de same-origin. CORS es cómo un servidor hace el opt-in: headers de respuesta que declaran qué origins, métodos y headers acepta. El navegador aplica; el servidor declara; tu código de frontend es solo el mensajero.'
  - question: '¿Qué es un origin, exactamente?'
    answer: 'La tripleta de esquema, host y puerto. https://app.example.com y https://api.example.com son origins distintos (difiere el host); también las versiones http y https de un mismo sitio (difiere el esquema), y :3000 vs :8080 en desarrollo (difiere el puerto). Toda decisión de CORS compara esas tres partes — nada más de la URL importa.'
  - question: '¿Cómo resolver un error de CORS?'
    answer: 'El navegador llamó a un origin distinto y la respuesta no traía un header Access-Control-Allow-Origin que coincidiera con el tuyo — así que el navegador impidió que tu script la leyera. La solicitud muchas veces llegó bien al servidor; el bloqueo es client-side, en la lectura. Por eso la corrección es siempre configuración del servidor — agregar tu origin a la lista permitida — y nunca código de frontend.'
  - question: '¿Qué es una solicitud de preflight?'
    answer: 'La verificación previa de permiso del navegador para solicitudes no simples: antes de enviar un PUT, un DELETE o cualquier cosa con headers personalizados, como un token de autorización, envía una solicitud OPTIONS preguntando "¿puedo?". Los headers del servidor responden qué métodos, headers y origins están permitidos; solo entonces vuela la solicitud real. Los preflights son cacheables vía Access-Control-Max-Age.'
  - question: '¿Por qué mi solicitud funciona en curl pero falla en el navegador?'
    answer: 'Porque CORS es aplicación por parte del navegador, no rechazo por parte del servidor. Herramientas como curl y las apps móviles nativas no tienen política de same-origin, así que leen la respuesta sin problema. El navegador aplica la política en nombre de su usuario — la diferencia que estás viendo es el punto de aplicación, y es también la prueba de que CORS no es control de acceso.'
  - question: '¿Access-Control-Allow-Origin: * es seguro?'
    answer: 'Para APIs genuinamente públicas y sin credenciales, sí. El wildcard está prohibido en modo con credenciales — los navegadores rechazan cookies contra él por diseño — y reflejar origins arbitrarios mientras se permiten credenciales es la mala configuración clásica que convierte a CORS de escudo en agujero. Las APIs privadas listan origins explícitamente.'
  - question: '¿Puedo simplemente deshabilitar CORS para arreglar el error?'
    answer: 'Solo en el sentido en que quitar la alarma de humo arregla el incendio. Las flags del navegador y los proxies permisivos enmascaran el síntoma en tu máquina mientras le entregan la falla a cada usuario. La corrección correcta toma minutos: configura el servidor (o el dashboard de la plataforma) para permitir los origins que deben llamarlo.'
  - question: '¿Cuál es la diferencia entre CORS, CSRF y CSP?'
    answer: 'Tres trabajos distintos. CORS gobierna qué origins pueden leer respuestas de un servidor. CSRF es un ataque — montarse en las cookies de un usuario para forjar solicitudes — contrarrestado con tokens y cookies SameSite, no con CORS. CSP es la política de la propia página restringiendo qué puede cargar y ejecutar, la herramienta anti-XSS. Siglas vecinas, mecanismos ortogonales.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'CORS — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS'
  - name: 'Fetch Standard — CORS protocol (WHATWG)'
    url: 'https://fetch.spec.whatwg.org/#http-cors-protocol'
  - name: 'Same-origin policy — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy'
  - name: 'Back4app documentation'
    url: 'https://www.back4app.com/docs'
  - name: 'Cross-origin resource sharing — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/Cross-origin_resource_sharing'
cta:
  title: 'Cross-origin que simplemente funciona'
  text: 'Las APIs de Back4app responden los preflights y envían los headers de CORS correctos desde el primer momento — tu app web llama al backend desde cualquier origin que permitas, mientras las apps nativas se saltan la ceremonia por completo. Sin hacks de proxy, nunca.'
  linkText: 'Empieza gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-09-03'
translationKey: cors-cross-origin-resource-sharing
---

**CORS es un mecanismo del navegador que permite al servidor declarar qué otros origins pueden llamarlo, relajando a propósito la política de same-origin.** Dos reencuadres disuelven la mayor parte de la confusión: quien lo aplica es el *navegador* (no el servidor — por eso curl funciona), y quien lo corrige es el *servidor* (no tu frontend — por eso ninguna cantidad de JavaScript ayuda). Todo lo demás son headers.

## Puntos clave

| Pregunta | Respuesta |
| --- | --- |
| El fundamento | Política de same-origin: los scripts no leen respuestas de otros origins por defecto |
| Un origin | esquema + host + puerto — los tres deben coincidir |
| CORS | Headers del servidor haciendo opt-in de origins específicos; el navegador aplica |
| Preflight | Un OPTIONS "¿puedo?" antes de solicitudes no simples |
| La verdad eterna | Los errores de CORS se corrigen en el servidor, punto |

## El protocolo entero, en el cable

```text
# Preflight: el navegador pregunta antes de un PUT con header de autenticación
OPTIONS /classes/Product HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: x-parse-session-token

# El permiso por escrito del servidor
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com   ← este origin puede leer
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: x-parse-session-token
Access-Control-Max-Age: 86400        ← cachea esta respuesta; sáltate el preflight de mañana

# Entonces, y solo entonces, vuela la solicitud real.
```

Cómo se ve desde el código de la aplicación — y la verdad de plataforma que las pestañas enseñan: CORS es un asunto del *navegador*, con el que las apps nativas nunca se topan:

**JavaScript:**

```javascript
// Browser JavaScript — Back4app JS SDK
// A cross-origin call that just works: the platform answers the
// preflight and sends the CORS headers, so the browser lets it through
Parse.initialize('APP_ID', 'JS_KEY');
Parse.serverURL = 'https://parseapi.back4app.com'; // different origin than your site

const products = await new Parse.Query('Product').find();
// No proxy hacks, no "disable CORS" — the server side is configured correctly.
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Native apps have no same-origin policy — CORS is a browser concern.
// Flutter Web, however, DOES enforce it: same browser rules apply there.
final query = QueryBuilder<ParseObject>(ParseObject('Product'));
final response = await query.query();
// Works identically on mobile and web because the server sends CORS headers.
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// No browser, no same-origin policy: CORS never applies to native iOS.
// The same backend serves browsers (with CORS headers) and apps alike.
let query = Product.query()
query.find { result in
  if case .success(let products) = result { render(products) }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// No browser, no same-origin policy: CORS never applies to native Android.
// The same backend serves browsers (with CORS headers) and apps alike.
val query = ParseQuery.getQuery<ParseObject>("Product")
query.findInBackground { products, e ->
  if (e == null) render(products)
}
```

## El flujo, decidido

```mermaid
flowchart TB
  accTitle: Cómo un navegador decide una solicitud cross-origin
  accDescr: Las solicitudes same-origin proceden directo; las solicitudes cross-origin simples se envían y su respuesta se verifica en busca de un header allow-origin; las solicitudes no simples disparan primero un preflight OPTIONS, y cualquier header ausente o que no coincida hace que el navegador bloquee la respuesta para la página.
  R["Un script hace una solicitud"] --> S{"¿Mismo origin?"}
  S -- sí --> OK["Procede, sin CORS de por medio"]
  S -- no --> T{"¿Solicitud simple?<br/>(GET/HEAD/POST, headers de la safelist)"}
  T -- sí --> D["Envía; verifica en la respuesta el<br/>Access-Control-Allow-Origin"]
  T -- no --> P["Preflight OPTIONS primero"]
  P --> D
  D -->|"el header coincide con el origin"| OK2["Respuesta legible"]
  D -->|"ausente / no coincide"| B["Bloqueada por el navegador<br/>(el error de la consola)"]
```

Dos detalles cargan con la mayoría de las sesiones de depuración: una **solicitud simple** (GET/HEAD/POST con headers de la safelist y content types comunes) se salta el preflight — por eso agregar un header `Authorization` de repente "rompe" un endpoint que funcionaba; y las **solicitudes con credenciales** lo aprietan todo — las cookies solo fluyen con `Access-Control-Allow-Credentials: true` *más* un origin exacto, nunca el wildcard, según [la especificación](https://fetch.spec.whatwg.org/#http-cors-protocol).

## Cómo corregir errores de CORS (error → causa → corrección)

| La consola dice | Lo que realmente pasó | Corrección (siempre server-side) |
| --- | --- | --- |
| No 'Access-Control-Allow-Origin' header | El servidor nunca hizo opt-in de tu origin | Agrega tu origin a la lista permitida |
| Origin not allowed by Access-Control-Allow-Origin | La allow-list existe; tú no estás en ella | Agrega el esquema+host+puerto exactos |
| Response to preflight… doesn't pass | OPTIONS sin manejar o headers incompletos | Responde el OPTIONS con métodos/headers |
| Wildcard '*' cannot be used with credentials | Cookies + `*` — combinación prohibida | Lista los origins explícitamente |
| Request header not allowed | Header personalizado fuera de la allow-list | Agrégalo a Access-Control-Allow-Headers |

Y el anti-arreglo que merece nombre: deshabilitar con flags del navegador y los proxies permisivos de desarrollo vuelven el error invisible *solo en tu máquina* — el despliegue sigue roto para los usuarios. La corrección real es una configuración de servidor medida en minutos.

## Casos de uso comunes

- **SPA + API en origins distintos** — app.example.com llamando a api.example.com: el caso cotidiano para el que existe CORS.
- **Desarrollo local** — localhost:3000 contra un backend real; permite el origin de desarrollo, no apagues el escudo.
- **APIs públicas** — origin wildcard, sin credenciales: correcto y seguro para datos genuinamente públicos.
- **Plataformas multi-frontend** — varias apps, un backend, una lista explícita de origins por entorno.
- **Backends BaaS** — la plataforma responde los preflights y envía los headers; tu trabajo se reduce a declarar los origins permitidos.

## Wildcard vs. origins explícitos: matriz de decisión

| Configuración | Correcta cuando… | Nunca cuando… |
| --- | --- | --- |
| Wildcard `*` | API pública, sin credenciales | Existen cookies o sesiones de usuario |
| Lista explícita de origins | APIs privadas, apps con credenciales | — (esta es la respuesta por defecto) |
| Reflejar el origin de la solicitud | Casi nunca | Combinada con credenciales — el agujero clásico |
| Listas por entorno | Higiene de dev/staging/prod | Producción heredando las entradas localhost de dev |

Un reencuadre de seguridad cierra la matriz: CORS **no es control de acceso** — las apps nativas y los servidores lo ignoran por completo, así que protege a los *usuarios del navegador* de sitios maliciosos, no a tu API de sus llamadores. La autenticación y los [permisos en la capa de datos](/glossary/data-layer-vs-application-layer-security/) hacen ese trabajo; CORS solo decide qué scripts de qué sitios pueden leer las respuestas.

## Limitaciones y trade-offs

- **Solo gobierna navegadores.** Cualquier cosa que no sea un navegador pasa de largo — nunca confundas una lista de origins con autorización.
- **Los preflights cuestan un round trip** en solicitudes no simples; el cache vía `Access-Control-Max-Age` es la corrección barata y olvidada.
- **La mala configuración falla cerrada y ruidosa** — bueno para la seguridad, brutal para depurar sin la tabla error→corrección de arriba.
- **Las listas de origins son estado de entorno.** Los origins de staging se cuelan en las configuraciones de producción; audita la lista como cualquier credencial.
- **CORS ≠ CSRF ≠ CSP.** Siglas vecinas, defensas separadas — las cookies aún necesitan protección SameSite/token, las páginas aún necesitan una content policy, y CORS se encarga solo de la lectura cross-origin.

## CORS en Back4app

Back4app es una plataforma open-source de Backend as a Service (BaaS) que combina base de datos gestionada, APIs REST y GraphQL generadas automáticamente, autenticación, almacenamiento de archivos y funciones serverless con Cloud Code. La tarea de CORS llega resuelta: las APIs de la plataforma responden los preflights y envían los headers correctos, así que las apps de navegador llaman al backend desde los origins permitidos sin hacks de proxy — la pestaña de JavaScript de arriba es la experiencia entera — mientras las pestañas de Flutter, Swift y Kotlin demuestran la verdad más silenciosa: los clientes nativos nunca se topan con la ceremonia. La seguridad real se queda donde pertenece: sesiones, ACLs y permisos a nivel de clase aplicados server-side en cada solicitud, venga del origin que venga.
