Configure CORS in .NET

We need to configure CORS in .NET (or really in any other language) when an application’s front-end and back-end are being served from different domains, aka origins. And more than likely, during development, both the front-end and back-end will be running from different ports on localhost.

But what is CORS?

Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.

From MDN

Basically, the server telling the browser “Hey, I only allow domains configured in my CORS policy, are you one of those?”

Enable CORS in .NET

CORS in .NET is enabled via middleware as follows

// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder
  .services
  .AddCors(...);

var app = builder.Build();
app.UseCors("PolicyName");

UseCors must be placed after UseRouting and before UseAuthorization. This is to ensure that CORS headers are included in the response for both authorized and unauthorized calls. (From the official docs)

Configure CORS in .NET

It is important to have the front-end origin as a configuration in appsettings.json so that when deploying to upper environments and production, a configuration transformation can happen.

{
  "CorsSettings": {
    "FrontendOrigin": "http://localhost:3050"
  }
}

Rather than having the configuration in Program.cs, I like to create a static class and a static method returning an Action.

// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder
  .services
  .AddCors(Cors.Configure(builder.Configuration)); // Static method that takes in IConfiguration

var app = builder.Build();
app.UseCors(Cors.FrontEndPolicyName); // Policy name as a static prop in Cors class

In my static Cors class, I read the front-end origin setting to use in the configuration.

// Cors.cs
public static class Cors
{
    public const string FrontEndPolicyName = "AllowFrontEnd";

    public static Action<CorsOptions> Configure(IConfiguration configuration)
    {
        var frontendOrigin = configuration
            .GetSection(nameof(CorsSettings))
            .Get<CorsSettings>()?
            .FrontendOrigin;
        
        // Only in .NET 8. In .NET 7 use .ThrowIfNullOrEmpty
        ArgumentException.ThrowIfNullOrWhiteSpace(frontendOrigin, nameof(frontendOrigin)); 

        return options =>
        {
            options
                .AddPolicy(name: FrontEndPolicyName,
                    policy =>
                    {
                        policy
                            .WithOrigins(frontendOrigin)
                            .AllowAnyHeader()
                            .AllowCredentials();
                        policy.WithMethods("POST","GET");
                    }
                );
        };
    }
}
  • WithOrigins – Configure your front-end origin, or origins if more than one
  • AllowAnyHeader – As the name implies, allow all headers from the browser. Use WithHeaders if only allowing specific headers
  • AllowCredentials – This is required if you have a login page. The front-end will send credentials to the server and the server will respond with Access-Control-Allow-Credentials: true. The server will block the request otherwise.
  • WithMethods – Allow specific HTTP request methods. Use AllowAnyMethod to allow all HTTP request methods.

BONUS! Configure Fetch API on the Front-End

fetch(`URL`, {
  method: 'POST',
  mode: 'cors',
  credentials: 'include',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify('{}'),
});

Mode cors must be included as an option in the request. credentials must also be included.

If credentials are not included, the request will not include the authentication cookie, and authenticated routes will not be reached.

If you liked this tutorial, share it on your social media and you can follow me on Twitter or LinkedIn.


Consider giving back by getting me a coffee (or a couple) by clicking the following button:

Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.