.NET Web API, Vue 3, NGINX - Reverse Proxy Doesn't Seem to be Working and Getting CORS 401 Unauthorized Issue - Where am I going wrong?

Viewed 54

I am battling with a couple of issues and it is driving me insane, so was hoping to get some help. I am a relatively new dev, so not as knowledgeable as I would like about all of this.

I have a .NET Web API, which I have published and is hosted via Kestrel on http://localhost:5000

I have a Vue 3 app, which is built and hosted on Nginx at http://localhost(:80)

There are two issues. Firstly, I have tried to set up a Reverse Proxy, so that when going to http://localhost/api/rmr it will redirect to the actual API at http://localhost:5000/api/rmr - When I visit http://localhost/api/rmr I get an error 400 page

The second issue, which I think is caused by the first, is that I am running into a CORS problem. Firstly it was an origin issue, but after fiddling I now just get 401 Unauthorized.

Following info on the internet, I am convinced the API side of things is correct, but it is only my second day of using Nginx so that could be where the issue is.

My Program.cs file looks like this;

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(
        policy =>
        {
            policy.WithOrigins("http://localhost:8080", "http://localhost:5000", "http://localhost")
            .AllowAnyHeader()
            .AllowAnyMethod()
            .AllowCredentials();
        });
});

#if DEBUG
builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);
#else

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("127.0.0.1"));
    options.KnownProxies.Add(IPAddress.Parse("127.0.0.1:5000"));
    options.KnownProxies.Add(IPAddress.Parse("127.0.0.1:80"));
});

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
   .AddNegotiate();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});
#endif 

builder.Services.AddScoped<RawcliffeDatastoreContext>();
builder.Services.AddScoped<IWSDatastoreContext>();
builder.Services.AddAutoMapper(typeof(MapperConfig));
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

//Below line is used to ignore Reference Loops - Don't keep in, actually fix the problem 
builder.Services.AddControllers().AddJsonOptions(x =>
                x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);

var app = builder.Build();

app.UseCors();

#if !DEBUG
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
#endif

app.UseAuthentication();
app.UseAuthorization();

// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
//{
app.UseSwagger();
    app.UseSwaggerUI();
//}

app.MapControllers();

//app.UseHttpsRedirection();
app.Urls.Add(baseAddress);
//app.Urls.Add(httpsAddress);

app.Run();

An example of a GET method looks like this;

getCurrentUser(): void
{
  fetch(apiURL + 'CurrentUser', 
  {
    headers: 
    {
      'Accept': 'application/json',
      'Content-Type': 'application/json' ,
    },
  })
  .then(response => 
    {
      return response.json();
    })
    .then((data) =>
    {
      this.currentUser = { userName: null, isAdmin: null, isPowerUser: null, area: null };

      this.currentUser = new User(data.userName.toLowerCase(), data.permissions[0].isAdmin, data.permissions[0].isPowerUser, data.permissions[0].area);
    })
  },

My nginx.conf file is currently like so:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    proxy_set_header Host $host;
    proxy_pass_request_headers on;

    gzip on;
    gzip_proxied any;

    map $sent_http_content_type $expires {
        default off;
        ~image/ 1M;
    }

    server 
    {
        listen      80;
        server_name localhost;    
        charset utf-8;
        root    C:/nginx/html/rmr/dist;
        index   index.html;
        #Always serve index.html for any request
        location / {
            root C:/nginx/html/rmr/dist;
            try_files $uri $uri/ /index.html;
            proxy_set_header   Connection $http_connection;

            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow_Credentials' 'true';
            add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
        }  
        location /api/rmr/ {
            proxy_pass         http://127.0.0.1:5000/api/rmr/;
            proxy_http_version 1.1;
            # proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection keep-alive;
            proxy_set_header   Host $host;
            # proxy_cache_bypass $http_upgrade;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;
            proxy_set_header   Connection $http_connection;

            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow_Credentials' 'true';
            add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
        }  
    }
}

Not sure if useful, but here are the request and response headers:

GET /api/rmr/CurrentUser HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: en
Connection: keep-alive
Content-Type: application/json
DNT: 1
Host: localhost:5000
Origin: http://localhost
Referer: http://localhost/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.33
sec-ch-ua: "Microsoft Edge";v="105", " Not;A Brand";v="99", "Chromium";v="105"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"


HTTP/1.1 401 Unauthorized
Content-Length: 0
Date: Sat, 10 Sep 2022 16:49:29 GMT
Server: Kestrel
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost
Vary: Origin
WWW-Authenticate: Negotiate

Thanks in advance for any help or information provided. If you need further information please let me know.

0 Answers
Related