DEV Community

Cover image for Yet another CORS in Umbraco Post
Jason Elkin
Jason Elkin

Posted on

Yet another CORS in Umbraco Post

I don't know how many blog, forum, and Discord posts I've read about how to set up CORS for a headless site in Umbraco. It feels like a lot. None of them worked for me 😥

It's probably just the usual problem of incorrect middleware order, which is always slightly tricky in Umbraco as some of the pipeline configuration is abstracted away.

What am I trying to do?

POST a form, via the Fetch API, from the frontend of my Headless site to my Umbraco instance backend.

The Problem

CORS. It's there to keep us all safe, but it can be a pain to configure.

An error message from a CORS failure

Fortunately there's a built-in CORS middleware in ASP.NET Core that can be configured

The Catch

I can't modify Startup.cs. Well, I could but it would ruin my project's architecture. The headless features are added in a separate assembly to the site's Core and Web code. The idea is that we can just drop the headless library into a baseline project to "switch on" headless functionality.

The Solution

Below is what is now working for me.

This composer lives in my BaseProject.Headless library and adds the appropriate CORS, so long as a frontend URI is set.

public class Composer : IComposer
{
    private const string FrontendCorsPolicyName = "FrontendCorsPolicy";

    public void Compose(IUmbracoBuilder builder)
    {

        if (Uri.TryCreate(builder.Config.GetSection("Headless:FrontendUrl")?.Value, UriKind.Absolute, out Uri? frontendUri))
        {
            builder.Services.AddCors(options =>
            {
                options.AddPolicy(FrontendCorsPolicyName, corsPolicyBuilder =>
                {
                    corsPolicyBuilder.WithOrigins(frontendUri.ToString())
                    .SetIsOriginAllowed(origin => new Uri(origin).Host == "localhost")
                    .AllowAnyHeader()
                    .AllowAnyMethod();
                });
            });

            builder.Services.Configure<UmbracoPipelineOptions>(options =>
            {
                options.AddFilter(new UmbracoPipelineFilter(FrontendCorsPolicyName)
                {
                    PrePipeline = app =>
                    {
                        app.UseCors(FrontendCorsPolicyName);
                    },
                });
            });
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Of special note is this:

corsPolicyBuilder.SetIsOriginAllowed(origin => 
  new Uri(origin).Host == "localhost"
)
Enter fullscreen mode Exit fullscreen mode

This is here because we can't guarantee devs running the frontend locally will be using any specific port (or scheme) - this should probably be wrapped in an environment check.

Top comments (0)