CORS on ASP.NET

⚠️ Security Warning: Using Access-Control-Allow-Origin: * allows any website to access your resources. Always specify exact origins in production.
💡 Recommendation: For new applications, use ASP.NET Core which has superior CORS support. The legacy ASP.NET Framework is in maintenance mode. For more information, see the official ASP.NET Core CORS documentation and legacy Web API 2 documentation.

ASP.NET Core (Recommended for New Projects)

ASP.NET Core has first-class CORS support built-in. This is the recommended approach for all new .NET applications.

Method 1: Specific Origin (Recommended)

// Program.cs (ASP.NET Core 6+)
var builder = WebApplication.CreateBuilder(args);

// Add CORS policy
builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.WithOrigins("https://example.com")
              .AllowAnyMethod()
              .AllowAnyHeader();
    });
});

builder.Services.AddControllers();

var app = builder.Build();

// Enable CORS middleware
app.UseCors();

app.MapControllers();
app.Run();

Method 2: Multiple Origins

Allow multiple specific origins (issue #146):

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.WithOrigins(
            "https://example.com",
            "https://app.example.com",
            "https://admin.example.com"
        )
        .AllowAnyMethod()
        .AllowAnyHeader();
    });
});

Method 3: With Credentials

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.WithOrigins("https://example.com")
              .AllowAnyMethod()
              .AllowAnyHeader()
              .AllowCredentials(); // Enable credentials
    });
});

Method 4: Named Policies

Define different policies for different endpoints:

builder.Services.AddCors(options =>
{
    // Restricted policy for APIs
    options.AddPolicy("ApiPolicy", policy =>
    {
        policy.WithOrigins("https://example.com")
              .WithMethods("GET", "POST")
              .WithHeaders("Content-Type", "Authorization")
              .AllowCredentials();
    });

    // Open policy for public endpoints
    options.AddPolicy("PublicPolicy", policy =>
    {
        policy.AllowAnyOrigin()
              .WithMethods("GET")
              .AllowAnyHeader();
    });
});

// Apply to specific endpoints
app.MapControllers().RequireCors("ApiPolicy");

Method 5: Per-Controller/Action

using Microsoft.AspNetCore.Cors;

[ApiController]
[Route("api/[controller]")]
[EnableCors("ApiPolicy")] // Apply to controller
public class DataController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok(new { message = "CORS enabled" });
    }

    [HttpPost]
    [EnableCors("PublicPolicy")] // Override for specific action
    public IActionResult Post([FromBody] Data data)
    {
        return Ok(data);
    }
}

ASP.NET Framework (Legacy)

For applications still using ASP.NET Framework (not Core):

ASP.NET Web API 2

Install the NuGet package:

Install-Package Microsoft.AspNet.WebApi.Cors

Enable in WebApiConfig.cs:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Enable CORS
        var corsAttr = new EnableCorsAttribute(
            origins: "https://example.com",
            headers: "*",
            methods: "*"
        );
        config.EnableCors(corsAttr);

        // Other Web API configuration...
        config.MapHttpAttributeRoutes();
    }
}

Or use the attribute on controllers:

[EnableCors(origins: "https://example.com", headers: "*", methods: "*")]
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        return Ok(new { message = "CORS enabled" });
    }
}

ASP.NET Web Forms / MVC (Without Web API)

If you don't have access to configure IIS, add headers in Global.asax or page code:

// Global.asax.cs
protected void Application_BeginRequest(object sender, EventArgs e)
{
    string origin = Request.Headers["Origin"];
    string[] allowedOrigins = {
        "https://example.com",
        "https://app.example.com"
    };

    if (allowedOrigins.Contains(origin))
    {
        Response.AppendHeader("Access-Control-Allow-Origin", origin);
        Response.AppendHeader("Vary", "Origin");
        Response.AppendHeader("Access-Control-Allow-Credentials", "true");
    }

    Response.AppendHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    Response.AppendHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");

    // Handle preflight
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AppendHeader("Access-Control-Max-Age", "86400");
        Response.StatusCode = 204;
        Response.End();
    }
}

Or in individual pages:

// In Page_Load or button click handler
Response.AppendHeader("Access-Control-Allow-Origin", "https://example.com");

Note: This approach is compatible with IIS6, IIS7 Classic Mode, and IIS7 Integrated Mode.

Testing Your CORS Configuration

For comprehensive testing instructions including curl commands, browser DevTools usage, and troubleshooting common CORS errors, see the CORS Testing Guide.

Who’s behind this

Monsur Hossain and Michael Hausenblas

Contribute

The content on this site stays fresh thanks to help from users like you! If you have suggestions or would like to contribute, fork us on GitHub.

Buy the book

Save 39% on CORS in Action with promotional code hossainco at manning.com/hossain