Search code examples
c#asp.net-coresession-cookiescredentialsasp.net-authorization

How to include Access-Control-Allow-Credentials in ASP .Net Core app?


Are there an explicit "Access-Control-Allow-Credentials" attribute to explicitly allow credentials to be sent with a request to a specific client site?

I have tried the following

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      builder =>
                      {
                          builder.WithOrigins("http://my-account-name.github.io",
                                              "http://my-account-name.github.io/My-repository",
                                              "https://my-account-name.github.io",
                                              "https://my-account-name.github.io/My-repository");
                      });
});
...

app.UseCors(MyAllowSpecificOrigins);

Not working solution source

And I get the "CORS" policy restriction in Chrome console nevertheless for those request that include credential headers and / or authorize cookies. Other requests (that don't include credentials) are passing fine with cors fetch() from JS.


Solution

  • The complete solution to the CORS Cookie Authorization is the SameSite = None; cookie policy (which you have to tell the browser explicitly from your server)

    // Controller.cs
        [EnableCors("_allowSpecific")] // !!!
        public class YourController : Controller
    // ...
    
    // Startup.cs (.Net 5) / Program.cs (.Net 6-7 +)
            string MyAllowSpecificOrigins = "_allowSpecific";
    
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddSession(options =>
                {
                    options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None; // !!!
                });
                services.AddCors(options => {
                    options.AddPolicy(name: MyAllowSpecificOrigins,
                        policy => { policy.WithOrigins( "http://your-domain.your-site.com", "https://your-domain.your-site.io", "http://your-domain.your-site.io"
    #if DEBUG // Use this for debugging CORS in NPM on another localhost port 
                            , "http://localhost:8081", "https://localhost:8081", "http://127.0.0.1:8081", "http://192.168.1.64:8081"
    #endif
                        ).AllowAnyHeader().AllowAnyMethod().AllowCredentials(); 
                    });
                });
                services.Configure<CookiePolicyOptions>(options => {
                    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                    options.CheckConsentNeeded = context => true; 
                    options.MinimumSameSitePolicy = SameSiteMode.None; // !!!
                });
    
                // ADD your services, DbContexts, Identity, Configure<IdentityOptions>, AddDefaultIdentity<IdentityUser>, AddRoles<IdentityRole>, AddEntityFrameworkStores<ApplicationDbContext>, ConfigureApplicationCookie, AddDatabaseDeveloperPageExceptionFilter, AddSingleton<IHttpContextAccessor>, AddRazorPages, AddControllersWithViews, AddLogging, 
    
                services.ConfigureApplicationCookie(options => {
                    // Cookie settings
                    options.Cookie.SameSite = SameSiteMode.None; // !!!
                    options.Cookie.HttpOnly = true;
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(10000);
                    options.SlidingExpiration = true;
                });
            }
    
            public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IWebHostEnvironment env, Microsoft.Extensions.Hosting.IHostApplicationLifetime appLifetime)
            {
                // ...
                app.UseCookiePolicy(new CookiePolicyOptions {
                    MinimumSameSitePolicy = SameSiteMode.None // !!!
                });
                // app.UseRouting(); ...
    
                app.UseCors(MyAllowSpecificOrigins); // ? 1) not sure whether you need to use both, but it works
                app.UseAuthentication();
                app.UseAuthorization();
                app.UseCors(MyAllowSpecificOrigins); // ? 2) not sure if you need to use both, but it works
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Home}/{action=Index}/{id?}") 
                    .RequireCors(MyAllowSpecificOrigins); // !!!
                    endpoints.MapRazorPages().RequireCors(MyAllowSpecificOrigins); // !!!
                    endpoints.MapControllers().RequireCors(MyAllowSpecificOrigins); // !!!
                });
            }
    //...
    

    Not only this setup will allow you to use CORS autherization (using cookie headers), this will also allow Chrome to block any request from other than "_allowSpecific" origins. I had to spend almost a year to figure this out.