Runtime CORs policy with ASP.NET Core

If you are developing APIs within ASP.NET Core that are accessed by JavaScript clients, then you will want to enable Cross-Origin Resource Sharing (CORS) as described in the official Microsoft docs.

This involves installing the Microsoft.AspNetCore.Cors package and configuring services.AddCors() and the app.UseCors() middleware if you wish to configure CORs for your entire application.

You can either use a CORs policy builder with app.UseCors() or define some named policies with services.AddCors() and then specify the policy name with app.UseCors().

This all works fine if you know the data required for your CORs policy at design time, for example the list of allowed origins.

However, if you need to need to retrieve or build your CORs policy at runtime, then you can use a custom CORs policy provider.

Under the covers, services.AddCors() adds an implementation of ICorsPolicyProvider called DefaultCorsPolicyProvider. This interface has a single method:

public interface ICorsPolicyProvider
{
    Task<CorsPolicy> GetPolicyAsync(
        HttpContext context, string policyName);
}

You can see that it can return a CorsPolicy by policy name, as well as having access to the current HTTP context.

If you wish to build a CORs policy based from run time data, or read allowed origins from a data store then you can register your own implementation of ICorsPolicyProvider:

services.AddCors();
services.AddTransient<ICorsPolicyProvider, CustomCorsPolicyProvider>();

Your implementation can take additional registered services, for example a repository:

internal class CustomCorsPolicyProvider : ICorsPolicyProvider
{
    private readonly IAllowedCorsOriginRepository allowedCorsOriginRepository;

    public CustomCorsPolicyProvider(IAllowedCorsOriginRepository allowedCorsOriginsRepository)
    {
        this.allowedCorsOriginRepository = allowedCorsOriginsRepository 
            ?? throw new ArgumentNullException(nameof(allowedCorsOriginsRepository));
    }

    public async Task<CorsPolicy> GetPolicyAsync(HttpContext context, string policyName)
    {
        var allowedOrigins = await this.allowedCorsOriginRepository
            .GetAllowedOrigins(policyName);

        return new CorsPolicyBuilder()
            .AllowAnyHeader()
            .AllowAnyMethod()
            .AllowCredentials()
            .WithOrigins(allowedOrigins.ToArray())
            .Build();
    }
}

Here, we’re allowing any header and method in the CORs policy, but reading the list of allowed origins from a custom IAllowedCorsOriginRepository. This could read values from a database or web service for example.

You can also cache results via a decorated IAllowedCorsOriginRepository.

There is an open issue with ASP.NET Core where CORs headers are not returned in error responses. This behaviour has been fixed in the 2.2.0 preview, but you can use the supplied workaround in the short term.