How to set up a CORS policy in Umbraco 12

Posted written by Paul Seal on July 03, 2023 Umbraco

This post shows you how to set up CORS in Umbraco

Why might you need it?

If you are going to be using the headless APIs in Umbraco 12 then you might find that the API calls are failing, like I did.

To fix that you might need to add a CORS policy.

After doing some digging and asking some friends in the community, I have found this solution, you do it all in the Startup.cs file:

1. Add a private variable to contain the name of the CORS policy.

namespace MyProject
{
    public class Startup
    {
        private readonly IWebHostEnvironment _env;
        private readonly IConfiguration _config;
        private readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

2. In the ConfigureServices method, add the Cors service:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy(name: MyAllowSpecificOrigins,
            policy  =>
            {
                policy.WithOrigins("https://headlesstest.localtest.me");
            });
    });

    services.AddUmbraco(_env, _config)
        .AddBackOffice()
        .AddWebsite()
        .AddDeliveryApi()
        .AddComposers()
        .Build();
}

3. Now we need to tell it to use Cors and this is the most important part

The order of where we call this really matters. It has to be called directly between .UseRouting(); and .UseAuthentication();

So to achieve this we modify the Configure method, to give us more control.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseUmbraco()
        .WithCustomMiddleware(u =>
        {
            u.RunPrePipeline();

            u.UseUmbracoCoreMiddleware();
            u.AppBuilder.UseUmbracoMediaFileProvider();
            u.AppBuilder.UseStaticFiles();
            u.AppBuilder.UseUmbracoPluginsStaticFiles();
            u.AppBuilder.UseRouting();
            u.AppBuilder.UseCors(MyAllowSpecificOrigins);
            u.AppBuilder.UseAuthentication();
            u.AppBuilder.UseAuthorization();
            u.AppBuilder.UseRequestLocalization();
            u.AppBuilder.UseSession();

            u.RunPostPipeline();
            u.UseBackOffice();
            u.UseWebsite();
        })
        .WithEndpoints(u =>
        {
            u.UseInstallerEndpoints();
            u.UseBackOfficeEndpoints();
            u.UseWebsiteEndpoints();
        });
}

Here is the complete file:

namespace MyProject
{
    public class Startup
    {
        private readonly IWebHostEnvironment _env;
        private readonly IConfiguration _config;
        private readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

        /// <summary>
        /// Initializes a new instance of the <see cref="Startup" /> class.
        /// </summary>
        /// <param name="webHostEnvironment">The web hosting environment.</param>
        /// <param name="config">The configuration.</param>
        /// <remarks>
        /// Only a few services are possible to be injected here https://github.com/dotnet/aspnetcore/issues/9337.
        /// </remarks>
        public Startup(IWebHostEnvironment webHostEnvironment, IConfiguration config)
        {
            _env = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment));
            _config = config ?? throw new ArgumentNullException(nameof(config));
        }

        /// <summary>
        /// Configures the services.
        /// </summary>
        /// <param name="services">The services.</param>
        /// <remarks>
        /// This method gets called by the runtime. Use this method to add services to the container.
        /// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940.
        /// </remarks>
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy(name: MyAllowSpecificOrigins,
                    policy  =>
                    {
                        policy.WithOrigins("https://headlesstest.localtest.me");
                    });
            });

            services.AddUmbraco(_env, _config)
                .AddBackOffice()
                .AddWebsite()
                .AddDeliveryApi()
                .AddComposers()
                .Build();
        }

        /// <summary>
        /// Configures the application.
        /// </summary>
        /// <param name="app">The application builder.</param>
        /// <param name="env">The web hosting environment.</param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseUmbraco()
                .WithCustomMiddleware(u =>
                {
                    u.RunPrePipeline();

                    u.UseUmbracoCoreMiddleware();
                    u.AppBuilder.UseUmbracoMediaFileProvider();
                    u.AppBuilder.UseStaticFiles();
                    u.AppBuilder.UseUmbracoPluginsStaticFiles();
                    u.AppBuilder.UseRouting();
                    u.AppBuilder.UseCors(MyAllowSpecificOrigins);
                    u.AppBuilder.UseAuthentication();
                    u.AppBuilder.UseAuthorization();
                    u.AppBuilder.UseRequestLocalization();
                    u.AppBuilder.UseSession();

                    u.RunPostPipeline();
                    u.UseBackOffice();
                    u.UseWebsite();
                })
                .WithEndpoints(u =>
                {
                    u.UseInstallerEndpoints();
                    u.UseBackOfficeEndpoints();
                    u.UseWebsiteEndpoints();
                });
        }
    }
}

Thanks to Mike Chambers and Poornima Nayar for helping me with this.