Enable cross-origin requests in UmbracoApiController and Azure

What you will learn

In this article, I’ll show how you can resolve Umbraco CMS API CORS policy problems.

By the end of this short tutorial, you will know what steps you need to take to:

  • Configure CORS for Umbraco API
  • Consume Umbraco API from another domain
  • Fix Umbraco API CORS issues
  • Enable CORS for Azure WebApp

CORS policy issues overview

Recently I was struggling with the local angular app while retrieving the data from the Umbraco API endpoint.

The app was throwing the following error:

Access to XMLHttpRequest at 'http://testapi.piotrbach.com/umbraco/API/showcase/getdummydata' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status

You may have encountered this problem as well.

This is a very common error that means the CORS mechanism was not properly configured.

Why this is happening?

Browser security prevents a web page from making AJAX requests to another domain. This restriction is called the same-origin policy, and prevents a malicious site from reading sensitive data from another site. However, sometimes you might want to let other sites call your web API. Cross Origin Resource Sharing (CORS) is a W3C standard that allows a server to relax the same-origin policy. Using CORS, a server can explicitly allow some cross-origin requests while rejecting others. CORS is safer and more flexible than earlier techniques such as JSONP. This tutorial shows how to enable CORS in your Web API application.

What to do now?

Installing Microsoft AspNet Cors library using nuget package manager

  • Open Visual Studio
  • Go to Tools\Nuget Package Manager
  • Choose Package Manager Console
  • Install the package as follows: Install-Package Microsoft.AspNet.WebApi.Cors

Enablling CORS globally

To enable CORS globally in Umbraco CMS v8+ you can use composing technique:

  • Create WebApiCorsComponent
  • Create WebApiCorsComposer and wire up the WebApiCorsComponent
  • Execute GlobalConfiguration.Configuration.EnableCors() during component initialization (inside Initialize() method)
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
internal class WebApiCorsComposer : IComposer
{
   public void Compose(Composition composition)
   {
      composition.Components().Insert<WebApiCorsComponent>();
   }

   public class WebApiCorsComponent : IComponent
   {
      public void Initialize()
      {
         GlobalConfiguration.Configuration.EnableCors();
      }

      public void Terminate()
      {
      }
   }
}

Decorating controller/action with EnableCors attribute

Before that - include System.Web.Http.Cors namespace

[EnableCors(origins: "*", headers: "*", methods: "*")]
public class ShowcaseApiController : UmbracoApiController
{
    [HttpGet]
    public IHttpActionResult GetDummyData()
    {
        return Json("ok");
    }
}

Configuring HTTP methods and headers in Web.config

<httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
        <remove name="Server" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE, HEAD" />
        <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Accept, Authorization, Content-Type" />
      </customHeaders>
</httpProtocol>

You may skip setting headers and methods in web.config end specify them directly in Component with the following code: 

var cors = new EnableCorsAttribute(origins: "*",
   headers: "Origin, X-Requested-With, Accept, Authorization, Content-Type", 
   methods: "GET, POST, PUT, DELETE, OPTIONS");

GlobalConfiguration.Configuration.EnableCors(cors);
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
internal class WebApiCorsComposer : IComposer
{
   public void Compose(Composition composition)
   {
      composition.Components().Insert<WebApiCorsComponent>();
   }

   public class WebApiCorsComponent : IComponent
   {
      public void Initialize()
      {
         var cors = new EnableCorsAttribute(origins: "*",
            headers: "Origin, X-Requested-With, Accept, Authorization, Content-Type", 
            methods: "GET, POST, PUT, DELETE, OPTIONS");

         GlobalConfiguration.Configuration.EnableCors(cors);
      }

      public void Terminate()
      {
      }
   }
}

Enabling CORS for Azure WebApp

If you're using the Azure Web App Service - additionally, you may need to specify the exact origins that should be allowed to make cross-origin calls.

Due to Azure security settings, the connected domains accessing the Azure app should be specified. I noticed that many guys forget this step and once the web API is deployed & ready - it's still not working.

To configure the Azure app properly you need to take the following steps:

  • Open Azure portal
  • Go to the App services section
  • Find the app service
  • Go to the CORS section
  • Add origin, in my case "http://localhost:4200" (for local development)
  • Save new settings

Azure Umbraco CMS Web app enabling CORS

References:

https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api

Comments
Leave a Comment