ReactJS, Axios, .NET Core 5.0 WebAPI -- 401 Unauthorized

Viewed 721

Important Edit

I mentioned that I could hit the API endpoint directly, from Edge or Chrome, which is correct. HOWEVER, the following issue is apparently specific to Edge (Version 91.0.864.71). When I actually tried to hit the endpoint via the React application (using Axios), I got a 200 response and the data that I was expected. So Microsoft strikes again...and this becomes specifically a "why is this not working in Edge" question.

I can't "just use Chrome" because our company mandates Edge and I can't contradict the Powers That Be and tell users to "just use Chrome".

Original Question

I've been searching the Internet from one side to the other looking for insight into this issue, but so far I haven't been able to find any information that offers a solution.

On an intranet here at work, I have created and deployed a .NET Core 5.0 web API to IIS 8.5 on Windows 2012 R2. The API "works" because I can hit it from a browser (Edge or Chrome) and I get the response body I expect. I can also hit it from Postman, assuming I provide NTLM credentials -- the API is set to use Windows Authentication, with Anonymous Authentication disabled via the IIS console.

Startup.cs


public void ConfigureServices(IServiceCollection services)
{

    services.AddControllers();

    //Custom services for DI will go here.
    services.AddScoped<IExceptionSearch, ExceptionSearch>();
    services.AddAuthentication(IISDefaults.AuthenticationScheme);

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "PVSEXR", Version = "v1" });
    });
}


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger();
        app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "PVSEXR v1"));
    }

    app.UseRouting();
    app.UseAuthorization();

    //Our custom logging middleware
    app.UseAPILogging(Configuration["ConnectionStrings:LoggingConnection"], Configuration["AppSettings:DataGroupCode"]);

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Controller method example

[Authorize]
[HttpGet("clients")]
public IActionResult GetClients()
{
    //ReturnDataObject is a custom data transport wrapper
    ReturnDataObject _rdo = _exceptionSearch.GetClients();
    if (_rdo.OpStatus == "OK")
    {
        return Ok(JsonConvert.SerializeObject(_rdo));
    }else if(_rdo.OpStatus == "MT")
    {
        return NoContent();
    }
    else
    {
        return BadRequest(JsonConvert.SerializeObject(_rdo));
    }
}

CORS is being set within the web.config file, working through the IIS CORS Module.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!-- To customize the asp.net core module uncomment and edit the following section. 
  For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->

  <system.webServer>
    <handlers>
      <remove name="aspNetCore" />
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath=".\PVSEXR.exe" arguments="" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="InProcess" />
    <cors enabled="true">
      <add origin="http://localhost:3000" allowCredentials="true">
        <allowHeaders allowAllRequestedHeaders="true" />
      </add>
    </cors>
  </system.webServer>
</configuration>

I have a ReactJS app which is meant to consume this service. It's currently using Axios to perform a GET to the endpoint. Axios is setting withCredentials to TRUE.

//Axios method
export const GetClients = () => { 
    return axios.get(`${process.env.REACT_APP_API_BASE}/pvsexr/exceptionsearch/clients`, {withCredentials: true});
}

//Method calling the Axios method
useEffect(()=>{
    GetClients()
    .then(result=>{
        setClientList(result.data);
    })
    .catch(err=>{
        console.log(err);
    })
}, [])

I think that's all the code I have to offer unless anyone has a specific request.

The issue is that when hitting the clients endpoint from the ReactJS app, I get a 401 Unauthorized error. As I can hit the endpoint in the browser, and can access it via Postman by supplying NTLM credentials, it looks like the API is in good shape. That leaves the React side of the house. I've tried using plain ol' Fetch as well, but also got the same 401 result.

Sample DevTools for Axios 401 Unauthorized

What am I missing? My dev machine is logged into the domain, and although the web server is running in a different domain, I assume there's a trust relationship as Postman lets me through regardless of which domain I use in that app.

Thanks!

EDIT

Added code indicating that the Axios method returns the Promise structure, which is handled as a Promise where it's needed to be handled.

1 Answers

Well, folks, thanks for taking the time to read this post, and for future generations, here's the reason for the issue (not the solution):

My company distributes and "manages" our Edge installations, and manages any Chrome installs they find. In their infinite wisdom, they have DISABLED THIRD PARTY COOKIES in Edge...but not in Chrome.

When I hit the site (http://localhost:3000) in Edge, I get a 401. When it hit the site in Chrome, I do not. In Chrome I disabled third party cookies, and was able to successfully trigger the 401.

Since I cannot enable third party cookies in Edge, I'm going to have to see what I can do to either A) figure out what constitutes a "third party cookie" in relation to a web API and a website hosted on trusted domains, or B) impose a comany-deying mandate that it's "Chrome or Bust".

Thank you for coming to my TEDTalk.

Related