2

I'm developing an application on .NET Core 3.1 + Angular and everything was working fine until recently, when I was trying to implement Negotiate Authentication configuration to the backend. Anyway the issue persists even after reverting all the Authentication configuration so it may not be related.

I'm getting CORS error with description PreflightMissingAllowOriginHeader followed by 401 error.

CORS error + 401

CORS error request details

Below you can see my code. Out of frustration I have even allowed all origins, headers and methods, when I was trying to debug this issue.

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(name: MyAllowSpecificOrigins,
                builder => { builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials(); });
        });

// Tried both ^ and v

/*      services.AddCors(options =>
        {
            options.AddPolicy(name: MyAllowSpecificOrigins,
                builder => { builder.WithOrigins("http://localhost:4200").AllowAnyHeader().AllowAnyMethod().AllowCredentials(); });
        });*/
    .
    .
    .
    .

        services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();

    .
    .
    .
    .
    .
    }


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        /*            app.UseHttpsRedirection();*/

        app.UseRouting();

        app.UseCors(MyAllowSpecificOrigins);
        
        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers().RequireCors(MyAllowSpecificOrigins); // <--- Tried both with and without RequireCors
        });

    }

Angular WebReqService

readonly ROOT_URL: string;
readonly httpHeaders: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
readonly httpOptions = {
headers: this.httpHeaders,
withCredentials: true
};

constructor(private http: HttpClient) {
  this.ROOT_URL = 'http://localhost:5000';
}

get(uri: string): Observable<any> {
  return this.http.get<any[]>(`${this.ROOT_URL}/${uri}`, this.httpOptions);
}

The strangest about it is that if I try to access the API directly by calling the request in browser or in Insomnia with NTLM Authorization, everything works just fine. Only if I try to access the API from Angular FE, I get the error.

Any ideas what could be the cause and how to fix it? Also, I think that it's not caused by not being authorized to use the application, because as I said it works outside the Angular and also if user is not authorized, it's configured to return 403 instead of 401.

Martin819
  • 412
  • 2
  • 7
  • 26
  • Are you developing your angular application on localhost? – okihnjo May 05 '21 at 07:39
  • Yes, both BE and FE are on localhost. – Martin819 May 05 '21 at 07:40
  • okay so my team and I basically had the exact same problem, the only difference our BE was online, but maybe my solution works for you aswell. So try the following: Get yourself an http-client like postman and try to reach your BE. That should work, but still just for confirmation. After that, go to your browser and install an Add-On. In Firefox e.g., there is an Add-On Called "Cors Everywhere". Enable it, start your application and try reaching out again. Let me know if that changed something. – okihnjo May 05 '21 at 07:51
  • The **Provisional headers are shown** part shown in https://i.stack.imgur.com/aiGSO.png indicates the request isn’t actually being sent — that is, the request never reaches the `http://localhost:5000` server at all. So try force-reloading, and try in a different browser, or try from a different computer. And see https://stackoverflow.com/a/21179105/441757 for additional info. – sideshowbarker May 05 '21 at 07:56
  • @okihnjo I have been using Postman during the development and everything was working until I enabled the Authentication, because Postman doesn't support NTLM authentication (They have in beta, but a lot of issues is reported) and thus I get 401 when trying to reach the endpoint from Postman. Also, it's not possible for me to install any extensions, because I'm on corporate HW and everything including the browser extensions is blocked and managed by the admins. I will now try to use Insomnia, which should have better NTLM support and get back to you. – Martin819 May 05 '21 at 08:11
  • @sideshowbarker I have tried force-reload with no luck. Unfortunately, only other browser which I can use is IE, but since the app was never supposed to support IE, it doesn't work there. Also, I'm not able to use different computer. – Martin819 May 05 '21 at 08:14
  • @okihnjo I can now confirm that in Insomnia it works. I had to change Cors config back to "builder.WithOrigins("http://localhost:4200")...;" instead of "builder.AllowAnyOrigin()...", because apparently it's not allowed to have AnyOrigin and AllowCredentials at the same time. Anyway, it still doesn't work from the FE. So it works from Insomnia and I unfortunately, I cannot use the extension that you suggested. Do you have any other suggestion? – Martin819 May 05 '21 at 08:31
  • Unfortunately not really.. maybe you could try using a proxy, but I have never done that so I can not confirm if thats the way to go, though there a lot of articles regarding proxies and cors problems. Here is a link: https://www.positronx.io/handle-cors-in-angular-with-proxy-configuration/ – okihnjo May 05 '21 at 08:45
  • @okihnjo So, how did you fix it in your case? What was the issue? – Martin819 May 05 '21 at 09:13
  • Well, firstly there was a misconfiguration at the backend, but I dont know what exactly was misconfigured (I only do the frontend). Secondly, the backend, once deployed, didnt allow localhost to access the services, thats why I asked where you run your app at the beginning. After deploying the Angular app it worked, so thats why I ran the services locally aswell and added the cors plugin and that did it for me in dev mode. – okihnjo May 05 '21 at 09:29
  • Something is still blocking the request, perhaps something in your web config? I would also remove 'withCredentials: true' from your angular httpOptions. 401 is an un-authorized status. Could you try first by hitting an anoymus method, or removing authorization from your BE? – Zonaib May 31 '21 at 13:21

2 Answers2

1

You can try to setup Angular proxy.

1 - create a file proxy.conf.js at the root of your angular app with the following :

    const PROXY_CONFIG = [
     {
     context: ["/api"],
     target: "http://localhost:5000",
     secure: false,
     logLevel: "error",
     changeOrigin: true,
    }
   ];
   module.exports = PROXY_CONFIG;

2 - in angular.json in projects -> yourprojectname -> architect -> serve ->configurations -> development, add "proxyConfig": "proxy.conf.js"

 "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "configurations": {
            "production": {
              "browserTarget": "client:build:production"
            },
            "development": {
              "browserTarget": "client:build:development",
              "proxyConfig": "proxy.conf.js"
            }
          },

3 - in your Angular WebReqService, set this.ROOT_URL = 'http://localhost:4200';

Piero
  • 1,638
  • 1
  • 13
  • 14
  • Hi @Pierre, thank you for your answer. This indeed solved my issue. Only one thing, the "procyConfig" parameter has to be in serve-options and not serve-configurations. At least for me the file was ignored while defined in configurations and I had to put it in the options. – Martin819 Jun 01 '21 at 10:08
  • mm ok. this is because I'm using Angular 12. things have changed a little bit in angular.json – Piero Jun 01 '21 at 10:44
0

It should not be necessary to setup regular CORS for development on localhost in .NET Core 3.1/angular.

My best bet is that either something is wrong in your launchSettings.json, .csproj file or that you forgot to set the useSpa in your Configure method of startup.cs

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "pathToMyAngularRootFolder";

                if (env.IsDevelopment())
                {
                    spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
                }
            });
Bertramp
  • 376
  • 1
  • 15