Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CORS headers missing when deployed on Azure Web App / Azure API

I have created an OWIN hosted WebAPI 2. There's also a web app (AngularJS) that's using the API and acting as a client.

I've added the necessary code for the CORS to the Startup.cs, and hosted it in local IIS on a port different than the client and confirmed that it fixes the Cors issue.

Then, I deployed both apps to Azure (I've put both on the Azure as Web App, and I also tried putting the OWIN to the Azure API that is currently in preview) but - the preflight request now fails (no Access-Control-Allow-Origin present in the response).

Q: Is there some specific of Azure I'm not aware of? How come that OWIN isn't serving this header when deployed but it's working on localhost? I don't see any constraints in the properties window on Azure blades settings for the apps.

Notes:

About some specifics of the setup I'm using:

  • Using Owin, WebAPI2, Ninject, SignalR
  • Custom token is issued and provided in headers on each subsequent request, and is verified with a custom filter.
  • Cors I'm attempting for now is *

The relevant part of Startup.cs:

public void Configuration(IAppBuilder appBuilder)
{
    appBuilder.UseCors(CorsOptions.AllowAll);

    HttpConfiguration config = new HttpConfiguration();
    config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

    //bind IClientsNotifier with method returning singleton instance of hub
    var ninjectKernel = NinjectWebCommon.GetKernel();
    ninjectKernel.Bind<MySignalRHub>().ToSelf().InSingletonScope();
    ninjectKernel.Bind<QueryStringBearerAuthorizeAttribute>().ToSelf();

    GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(ninjectKernel);
    appBuilder.Map(
        "/signalr", map =>
    {
        map.UseCors(CorsOptions.AllowAll);
        var hubConfiguration = new HubConfiguration();
        map.RunSignalR(hubConfiguration);
    });

    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
       name: "DefaultApi",
       routeTemplate: "api/{controller}/{id}",
       defaults: new { id = RouteParameter.Optional }
    );

    config.Formatters.Remove(config.Formatters.XmlFormatter);

    config.Filters.Add(new NoCacheHeaderFilter()); //the IE9 fix for cache
    var resolver = new NinjectDependencyResolver(NinjectWebCommon.GetKernel());

config.Filters.Add((System.Web.Http.Filters.IFilter)resolver.GetService(typeof(WebApiAuthenticationFilter)));

    appBuilder.UseNinjectMiddleware(NinjectWebCommon.GetKernel);
    appBuilder.UseNinjectWebApi(config);
}

Additionally, I've commented out the following line from the web.config in order to support the OPTIONS HTTP request (otherwise, it was throwing HTTP error 405)

<system.webServer>
   <handlers>
     <!--<remove name="OPTIONSVerbHandler" />-->
     ...
like image 902
veljkoz Avatar asked Apr 20 '16 10:04

veljkoz


People also ask

How do I fix Azure Cors error?

In the allowed origins section, please make sure the origin URL which will call your APIM service, has been added. In some cases, you may only want to apply <cors> policy to the API or Operation level. In this case, you will need to navigate to the API or Operation, add the <cors> policy into the inbound policy there.

How do you add access control allow Origin header in Azure?

On the Azure Portal, navigate to your Web App. Navigate to API > CORS. There is now a checkbox for Enable Access-Control-Allow-Credentials . Check this box and press Save .


2 Answers

Actually, Azure website is supposed to manage CORS for you. I think you missed a handy Azure website blade:

Azure Websites CORS blade

If our own understanding is correct, the problem with this Azure middleware is that is allows you to configure nothing but allowed origins. It lacks an "allowed headers" manageable configuration, per-URL rules, and other useful CORS HTTP headers. Worse: it drops all CORS related headers from every single HTTP response it processes, before setting its own, so it doesn't even let you handle what it doesn't.

The good thing is that you can completely disable this middleware and manage CORS by your own means, you juste have to remove every single allowed origin (including *) from the CORS settings blade in the portal. Then you can use web.config or Web Api to handle it more specifically. See the documentation:

Don't try to use both Web API CORS and App Service CORS in one API app. App Service CORS will take precedence and Web API CORS will have no effect. For example, if you enable one origin domain in App Service, and enable all origin domains in your Web API code, your Azure API app will only accept calls from the domain you specified in Azure.

See also this related issue:

So the final answer is: If your application does not need a very specific CORS management, you can use Azure App Service CORS. Otherwise you will need to handle it yourself and disable all CORS configuration in the web app.

like image 157
Maxime Rossini Avatar answered Sep 21 '22 21:09

Maxime Rossini


In the end I went with easier way - removed all code-handling of CORS and simply put the headers in the web.config:

<configuration>
 <system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="http://my-client-website.azurewebsites.net" />
      <add name="Access-Control-Allow-Methods" value="*" />
      <add name="Access-Control-Allow-Headers" value="accept, content-type, x-my-custom-header" />
      <add name="Access-Control-Allow-Credentials" value="true" />
    </customHeaders>
  </httpProtocol>
 ...

(note that allow-origin doesn't have a slash at the end of the url!)

The allow-credentials part was to satisfy the SignalR, probably it could do without it.

If someone finds a reason as to why the coded way isn't working I'd like to know!

like image 43
veljkoz Avatar answered Sep 22 '22 21:09

veljkoz