(CORS C# ASP.NET Core) Enabling CORS for Specific CSS or JS Files

Static files are NOT accessible cross-origin if we call UseStaticFiles before UseCors. But if we reverse the order, every static file becomes accessible to permitted origins. So we have an all-or-none type of situation. CORS can either be disabled for every static file or disabled for none. This tutorial explains how to enable CORS for just a small subset of files, as done by the various CDN networks.
(Rev. 30-Sep-2022)

Categories | About |     |  

Parveen,

The order of UseCors and UseStaticFiles matters

We have already created a project, and you can obtain it from the downloads attached to this tutorial. I will now explain how the order of UserCors and UseStaticFiles affects the cross-origin behavior.

First of all open the solution explorer. We have added a folder called wwwroot to hold the static files. It contains a CSS file, as well as a JS file that we shall later try to access cross-origin.

Next open the program.cs file. Let's see it line-by-line.

First three lines are the usual code. After that we have defined a default cross-origin policy to allow cross origin requests from a third-party website.

The call to UseStaticFiles precedes UseCors - which means that static files will not be accessible cross-origin, even if done from the third-party site.


// UseStaticFiles precedes UseCors 
// so cross-origin policy will be ignored 

using Microsoft.AspNetCore.Cors.Infrastructure;

var builder = WebApplication.CreateBuilder();

builder.Services.AddRazorPages();

builder.Services.AddCors(options =>
{
  options.AddDefaultPolicy ( policy => 
  { 
    policy.WithOrigins("https://hoven.in"); 
  });
});

var app = builder.Build();

app.UseStaticFiles();

// applies the default policy to all files 
app.UseCors();

app.MapRazorPages();

app.Run();

Run the project and allow the home page to open.

Open the command prompt and type the following curl command.


// type in one single line 
curl  -i https://localhost:7276/css/site.css
      -H "origin:https://hoven.in"

// response headers 
// cross-origin request fails 

HTTP/1.1 200 OK
Content-Length: 57
Content-Type: text/css
Date: Wed, 17 Aug 20...
Server: Kestrel
Accept-Ranges: bytes
ETag: "1d8b1f7826316b9"

Hit enter to receive the response. We observe that there is no header for allow-cross-origin-requests. Thus, static files are not accessible even to the permitted origins.

Next let us change the precedence by moving UseCors before UseStaticFiles as you see here.

Now again run the project. And, again open the command prompt and type the same curl command again.


// CSS file test 

// type in one single line 
curl  -i https://localhost:7276/css/site.css
      -H "origin:https://hoven.in"

// cross-origin request succeeds 

HTTP/1.1 200 OK
Content-Length: 57
Content-Type: text/css
Date: Wed, 17 Aug 20...
Server: Kestrel
Accept-Ranges: bytes
Access-Control-Allow-Origin: https://hoven.in
ETag: "1d8b1f7826316b9"

This time the header Access-Control-Allow-Origin is sent by the server - which means the CORS policy was applied.

Let's also make a request to the javascript file.


// JS file test 

// type in one single line 
curl  -i https://localhost:7276/css/site.js
      -H "origin:https://hoven.in"

// cross-origin request succeeds 

HTTP/1.1 200 OK
Content-Length: 57
Content-Type: text/javascript
Date: Wed, 17 Aug 20...
Server: Kestrel
Accept-Ranges: bytes
Access-Control-Allow-Origin: https://hoven.in
ETag: "1d8b1f7826316b9"

We observe that the header Access-Control-Allow-Origin is again sent by the server - which means the CORS policy was applied to this JS file also.

Video Explanation (see it happen!)

Please watch the following youtube video:

The Problem Statement

It appears that there is no method to exclude some files while including others at the same time.

The problem, therefore, is how to apply CORS policy only to a specific CSS file or, say, to a given folder, while excluding the JS file.

The Solution

To solve this problem, start by defining a policy that will apply to the CSS file or that folder. After that use the OnPrepareResponse property to apply this policy when that resource is fetched.

Open the solution explorer and modify the program.cs file. I will now explain it line by line.

First add a named policy to the services collection. This policy allows cross-origin requests from a third party website.

Next call UseStaticFiles with an overload that accepts StaticFileOptions, and set the OnPrepareResponse property. The handler is used to add or change the response headers.

An if condition compares the name or path of the requested resource. We can now filter out all files except the CSS file we want to be accessible cross-origin.

First extract two cross-origin services from the services container. Then obtain the named cross-origin CorsPolicy. This is the policy that we want to apply to this request.

Construct a cross-Origin CorsResult based on this policy, and apply it to the response. Everything else is taken care of by the code executing behind the scenes.



using Microsoft.AspNetCore.Cors.Infrastructure;

var builder = WebApplication.CreateBuilder();

builder.Services.AddRazorPages();

const string POLICY_CSS = "PolicyCSS";

builder.Services.AddCors(options =>
{
  options.AddPolicy(POLICY_CSS, 
    policy => { 
      policy.WithOrigins("https://hoven.in"); 
    });
});

var app = builder.Build();

app.UseStaticFiles(options: new StaticFileOptions()
{
  OnPrepareResponse = async ctx =>
  {
    const String CSS_CORS = "site.css";

    if (CSS_CORS.Equals(ctx.File.Name))
    {
      // get services 
      var _corsPolicyProvider = 
        app.Services.GetRequiredService<ICorsPolicyProvider>();

      var _corsSvc = 
        app.Services.GetRequiredService<ICorsService>();

      // extract the policy for this CSS 
      var policy = 
        await _corsPolicyProvider
              .GetPolicyAsync(ctx.Context, POLICY_CSS);

      // apply this is the main part 
      if (policy != null)
      {
        CorsResult corsResult = 
          _corsSvc.EvaluatePolicy(ctx.Context, policy);

        _corsSvc.ApplyResult(corsResult, ctx.Context.Response);
      }
    }
  }
}
);

app.UseCors();

app.MapRazorPages();

app.Run();

Run the Project

Run the project again. And again open the command prompt and make a request to the CSS file.


// type in one single line 
curl  -i https://localhost:7276/css/site.css
      -H "origin:https://hoven.in"

// response 
// cross-origin request succeeds 

HTTP/1.1 200 OK
Content-Length: 57
Content-Type: text/css
Date: Wed, 17 Aug 20...
Server: Kestrel
Accept-Ranges: bytes
Access-Control-Allow-Origin: https://hoven.in
ETag: "1d8b1f7826316b9"

We observe that the Access-Control-Allow-Origin header is now present, as expected.

Let's finally verify if the JS file is now blocked from cross-site access.

Run the project again. And again open the command prompt and make a request to the JS file.


// JS file NOT accessible cross origin 

// type in one single line 
curl  -i https://localhost:7276/css/site.js
      -H "origin:https://hoven.in"

// repsonse 
// Access-Control-Allow-Origin is absent! 
// cross-origin request fails 

HTTP/1.1 200 OK
Content-Length: 22
Content-Type: application/javascript
Date: Wed, 17 Aug 2022 14:25:02 GMT
Server: Kestrel
Accept-Ranges: bytes
ETag: "1d8b24405aa5996"

We observe that the Access-Control-Allow-Origin header is absent, as expected. Thus we have learnt how to selectively allow cross origin requests to static files like CSS and JS files. Thanks!


This Blog Post/Article "(CORS C# ASP.NET Core) Enabling CORS for Specific CSS or JS Files" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.