Skip to main content
The Intent.AspNetCore.Cors module provides a standard CORS (Cross-Origin Resource Sharing) policy for ASP.NET Core applications, enabling your Web API to accept requests from different origins such as web browsers and mobile applications.

Overview

CORS is a security feature implemented by web browsers that restricts web pages from making requests to a different domain than the one serving the web page. This module configures CORS policies to allow controlled cross-origin access to your API.

What Gets Generated

CorsConfiguration

Configures CORS policies for your application:
public static class CorsConfiguration
{
    public static IServiceCollection AddCorsPolicy(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder =>
            {
                builder
                    .AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
            });
        });

        return services;
    }

    public static IApplicationBuilder UseCorsPolicy(this IApplicationBuilder app)
    {
        app.UseCors();
        return app;
    }
}

Key Features

Origin Control

Allow specific origins or all origins

Method Control

Specify allowed HTTP methods

Header Control

Configure allowed request headers

Credentials

Control cookie and credential sharing

Configuration Options

Allow All Origins (Development)

For development environments:
services.AddCors(options =>
{
    options.AddDefaultPolicy(builder =>
    {
        builder
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader();
    });
});
Do not use AllowAnyOrigin() in production! This allows any website to make requests to your API, which can be a security risk.

Specific Origins (Production)

For production environments:
services.AddCors(options =>
{
    options.AddDefaultPolicy(builder =>
    {
        builder
            .WithOrigins(
                "https://www.example.com",
                "https://app.example.com",
                "https://mobile.example.com")
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials();
    });
});

Named Policies

Define multiple CORS policies:
services.AddCors(options =>
{
    // Policy for web applications
    options.AddPolicy("WebAppPolicy", builder =>
    {
        builder
            .WithOrigins("https://webapp.example.com")
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials();
    });

    // Policy for mobile apps
    options.AddPolicy("MobileAppPolicy", builder =>
    {
        builder
            .WithOrigins("https://mobile.example.com")
            .WithMethods("GET", "POST", "PUT", "DELETE")
            .WithHeaders("Authorization", "Content-Type")
            .AllowCredentials();
    });

    // Policy for public APIs
    options.AddPolicy("PublicApiPolicy", builder =>
    {
        builder
            .AllowAnyOrigin()
            .WithMethods("GET")
            .AllowAnyHeader();
    });
});
Apply policies to controllers:
[EnableCors("WebAppPolicy")]
[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
    // All endpoints use WebAppPolicy
}

[ApiController]
[Route("api/public")]
public class PublicController : ControllerBase
{
    [EnableCors("PublicApiPolicy")]
    [HttpGet("products")]
    public ActionResult<List<ProductDto>> GetProducts()
    {
        // This endpoint uses PublicApiPolicy
    }
}

Configuration-Based Origins

Load allowed origins from appsettings.json:
{
  "CorsSettings": {
    "AllowedOrigins": [
      "https://www.example.com",
      "https://app.example.com"
    ]
  }
}
var allowedOrigins = configuration
    .GetSection("CorsSettings:AllowedOrigins")
    .Get<string[]>();

services.AddCors(options =>
{
    options.AddDefaultPolicy(builder =>
    {
        builder
            .WithOrigins(allowedOrigins)
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials();
    });
});

CORS Request Flow

Simple Request

For simple requests, the browser includes an Origin header:
GET /api/products HTTP/1.1
Host: api.example.com
Origin: https://webapp.example.com
The server responds with CORS headers:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://webapp.example.com
Content-Type: application/json

[{"id": 1, "name": "Product 1"}]

Preflight Request

For complex requests (e.g., with custom headers), the browser sends a preflight OPTIONS request:
OPTIONS /api/orders HTTP/1.1
Host: api.example.com
Origin: https://webapp.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type
The server responds:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://webapp.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 3600
Then the actual request is sent:
POST /api/orders HTTP/1.1
Host: api.example.com
Origin: https://webapp.example.com
Authorization: Bearer eyJhbGc...
Content-Type: application/json

{"customerId": 123, "items": [...]}

Advanced Configuration

Allow Credentials

Enable cookies and authentication headers:
builder
    .WithOrigins("https://webapp.example.com")
    .AllowAnyMethod()
    .AllowAnyHeader()
    .AllowCredentials(); // Enable credentials
When using AllowCredentials(), you cannot use AllowAnyOrigin(). You must specify explicit origins.

Expose Headers

Allow client to read custom response headers:
builder
    .WithOrigins("https://webapp.example.com")
    .AllowAnyMethod()
    .AllowAnyHeader()
    .WithExposedHeaders("X-Total-Count", "X-Page-Number", "X-Page-Size");
Client can now access these headers:
fetch('https://api.example.com/api/products')
  .then(response => {
    const totalCount = response.headers.get('X-Total-Count');
    console.log(`Total products: ${totalCount}`);
    return response.json();
  });

Preflight Max Age

Cache preflight responses:
builder
    .WithOrigins("https://webapp.example.com")
    .AllowAnyMethod()
    .AllowAnyHeader()
    .SetPreflightMaxAge(TimeSpan.FromHours(1)); // Cache for 1 hour

Specific Methods and Headers

Restrict to specific methods and headers:
builder
    .WithOrigins("https://webapp.example.com")
    .WithMethods("GET", "POST", "PUT", "DELETE")
    .WithHeaders("Authorization", "Content-Type", "Accept");

Per-Controller CORS

Apply CORS to specific controllers:
[EnableCors("SpecificPolicy")]
[ApiController]
[Route("api/public")]
public class PublicController : ControllerBase
{
    // This controller uses SpecificPolicy
}

[DisableCors]
[ApiController]
[Route("api/internal")]
public class InternalController : ControllerBase
{
    // CORS disabled for this controller
}

Environment-Specific Configuration

Configure CORS based on environment:
public static IServiceCollection AddCorsPolicy(
    this IServiceCollection services,
    IConfiguration configuration,
    IWebHostEnvironment environment)
{
    services.AddCors(options =>
    {
        if (environment.IsDevelopment())
        {
            options.AddDefaultPolicy(builder =>
            {
                builder
                    .AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
            });
        }
        else
        {
            var allowedOrigins = configuration
                .GetSection("CorsSettings:AllowedOrigins")
                .Get<string[]>();

            options.AddDefaultPolicy(builder =>
            {
                builder
                    .WithOrigins(allowedOrigins)
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials();
            });
        }
    });

    return services;
}

Middleware Order

CORS middleware must be placed correctly in the middleware pipeline:
var app = builder.Build();

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

app.UseCors(); // Must be after UseRouting() and before UseAuthorization()

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

app.MapControllers();

app.Run();

Testing CORS

Browser Developer Tools

Check CORS headers in browser DevTools Network tab:
  1. Open DevTools (F12)
  2. Go to Network tab
  3. Make a cross-origin request
  4. Look for Access-Control-* headers in the response

cURL Testing

Test with cURL:
# Simple request
curl -i -X GET \
  -H "Origin: https://webapp.example.com" \
  https://api.example.com/api/products

# Preflight request
curl -i -X OPTIONS \
  -H "Origin: https://webapp.example.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Authorization, Content-Type" \
  https://api.example.com/api/orders

Postman Testing

Postman does not enforce CORS restrictions. Use a browser or curl for accurate CORS testing.

Common Issues

Cause: CORS is not configured or origin is not allowedSolution:
  • Verify CORS middleware is added
  • Check the requesting origin is in allowed origins
  • Ensure middleware order is correct
Cause: Using AllowAnyOrigin() with AllowCredentials()Solution:
  • Replace AllowAnyOrigin() with WithOrigins("specific-origin")
  • Or remove AllowCredentials() if credentials aren’t needed
Cause: OPTIONS requests are not being handledSolution:
  • Ensure CORS middleware is before authentication
  • Check firewall/load balancer allows OPTIONS
  • Verify no [DisableCors] attribute on controller
Cause: Different CORS configuration per environmentSolution:
  • Check production configuration settings
  • Verify production origins are correctly specified
  • Check for HTTPS requirement in production

Security Considerations

  • Always validate origins in production
  • Use a whitelist of allowed origins
  • Consider using pattern matching for subdomains
  • Store allowed origins in configuration, not code
  • Only enable credentials when necessary
  • Must specify exact origins when using credentials
  • Consider the security implications of cross-origin cookies
  • Only allow necessary HTTP methods
  • Restrict headers to those actually needed
  • Use specific policies for different API sections
  • Log CORS violations
  • Monitor for unusual cross-origin requests
  • Review and update allowed origins regularly

Installation

Intent.AspNetCore.Cors

Dependencies

  • Intent.AspNetCore (>= 4.0.2)
  • Intent.Common.CSharp
  • Intent.OutputManager.RoslynWeaver

Next Steps

Controllers

Create endpoints that support CORS

Security

Add authentication with CORS

ASP.NET Core

Learn about the core infrastructure

Build docs developers (and LLMs) love