aspnet-core-cors-cross-origin-resource-sharing-guia

Configurar CORS en ASP.NET Core

  • 4 min

El CORS es un mecanismo con el que el servidor autoriza determinados accesos entre orígenes en los navegadores.

Tu API funciona perfecta. Haces las peticiones desde Swagger y te devuelve un 200 OK. Haces las peticiones desde Postman y funciona de maravilla. Te vas a tu proyecto de React/Angular, haces un fetch a la misma URL y… ¡BAM! Consola llena de letras rojas:

Access to fetch at ‘https://mi-api.com’ from origin ‘http://localhost:3000’ has been blocked by CORS policy.

¿Por qué tu API odia a tu Frontend? ¿Por qué Postman sí puede y Chrome no? No es que tu API falle. Es que el navegador te está “protegiendo” (aunque a veces parezca que solo quiere molestarte).

Vamos a entender por qué aparece el bloqueo y cómo configurarlo en ASP.NET Core.

Qué es la política del mismo origen

Para entender CORS, primero hay que entender su opuesto: la Política del Mismo Origen (Same-Origin Policy).

Por seguridad, los navegadores impiden por defecto que una web cargada en el Origen A (ej: localhost:3000) lea datos de un servidor en el Origen B (ej: localhost:5000).

Un “Origen” se define por: Protocolo + Dominio + Puerto.

  • http://example.com y https://example.com son orígenes distintos (protocolo).
  • localhost:3000 y localhost:5000 son orígenes distintos (puerto).

Si no existiera esta regla, una web maliciosa podría intentar hacer peticiones a facebook.com en segundo plano con tus cookies y robarte la sesión.

CORS al rescate

CORS (Cross-Origin Resource Sharing) es el mecanismo estándar para relajar esta seguridad de forma controlada. Es la forma que tiene el servidor (tu API) de decirle al navegador: “Tranquilo, conozco a los chicos de localhost:3000, déjales pasar”.

Importante: CORS es una política aplicada por los navegadores. Postman o una app móvil no la aplican, por eso no sufren este bloqueo.

CORS no sustituye a la autenticación ni impide que un cliente ajeno al navegador llame a la API.

Configurar CORS en ASP.NET Core

En .NET, configurar esto es un proceso de dos pasos: definir la Política (Servicios) y activar el Middleware.

Definir la política (builder.Services)

En Program.cs, antes de builder.Build(), definimos quién puede entrar.

var builder = WebApplication.CreateBuilder(args);

// Definimos una constante para el nombre, para no equivocarnos luego
var MisOrigenesPermitidos = "_misOrigenesPermitidos";

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MisOrigenesPermitidos,
                      policy =>
                      {
                          policy.WithOrigins("http://localhost:3000",
                                             "https://mi-web-produccion.com")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
                      });
});
Copied!
  • WithOrigins: La lista blanca de dominios. No pongas / al final.
  • AllowAnyHeader: Importante si usas JWT. Si no lo pones, el navegador bloqueará la cabecera Authorization y el login fallará.
  • AllowAnyMethod: Permite GET, POST, PUT, DELETE, etc.

Activar el middleware (app.UseCors)

En este punto la mayoría falla. El orden es crítico.

CORS debe ejecutarse después de UseRouting y antes de UseAuthorization. Es habitual colocarlo también antes de UseAuthentication, como en este ejemplo.

El navegador puede enviar una petición previa OPTIONS (preflight) para preguntar si el método y las cabeceras están permitidos. El middleware de CORS debe poder resolverla antes de que la autorización proteja el endpoint.

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

// ✅ AQUÍ: Justo antes de la seguridad
app.UseCors(MisOrigenesPermitidos);

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.Run();
Copied!

Desarrollo y producción

Durante el desarrollo, a veces es tedioso estar añadiendo cada puerto nuevo. Podemos ser más permisivos SOLO en desarrollo.

if (app.Environment.IsDevelopment())
{
    // "Barra libre" para desarrollo
    app.UseCors(x => x
        .AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader());
}
else
{
    // Política restrictiva para producción
    app.UseCors(MisOrigenesPermitidos);
}
Copied!

Peligro: No uses AllowAnyOrigin() como solución por defecto en producción si tu API maneja datos sensibles. Define orígenes concretos y revisa especialmente los casos con cookies o credenciales.

El caso especial de las credenciales

Si en lugar de JWT (Header) decides usar Cookies de sesión o autenticación de Windows, la configuración cambia. El navegador es más estricto aún.

  1. El frontend debe enviar withCredentials: true.
  2. El backend NO puede usar AllowAnyOrigin(). Debe especificar el origen exacto.
  3. El backend debe añadir .AllowCredentials().
policy.WithOrigins("http://localhost:3000") // Origen explícito obligatorio
      .AllowAnyHeader()
      .AllowAnyMethod()
      .AllowCredentials(); // 👈 Permite pasar Cookies
Copied!

Diagnosticar problemas de CORS

Si sigues viendo el error rojo:

  1. Mira la pestaña Network: Busca la petición fallida. ¿Es la petición real o una petición de tipo OPTIONS?
  2. Revisa el orden: ¿Está UseCors antes de UseAuthorization?
  3. Revisa los Headers: ¿Has puesto .AllowAnyHeader()? El header Authorization (donde va el JWT) suele ser bloqueado si no se permite explícitamente.
  4. Limpia la caché: A veces los navegadores guardan las respuestas de CORS. Abre una ventana de incógnito.