1

So here is my Cors initialization code:

        app.UseCors(builder =>
            builder.AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin());

And yet when I run PATCH I get the following error in Chrome 83:

Access to fetch at 'https://api-dev.myproject.com/api/mp' from origin 'https://users-dev.myproject.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Here is the code that is calling the api (from React):

  const response = await fetch(API_URL() + `/mp`, {
    method: 'PATCH',
    body: `"${JSON.stringify(mpForm.values)}"`,
    headers: {
      Authorization: 'Bearer ' + apiToken,
      'Content-type': 'application/json'
    }
  });

What could be going wrong here? Most API requests to this domain are just fine. It's just this one at the moment.

UPDATE

Just in case you are experiencing this exact issue, the root cause of this problem was the body line:

body: `"${JSON.stringify(mpForm.values)}"`,

and the issue was resolved by refactoring the API to work with a body like this instead:

body: JSON.stringify(mpForm.values),

The reason this was a problem was that the stringify function embedded double quotes in the return value, resulting in a string like this being passed:

'"{"foo":"bar"}"'

which then caused the CORS error.

dylanT
  • 942
  • 1
  • 8
  • 24
  • Show the Chrome trace of this request, and the trace of a similar request to the same API that works. We want to look at headers and the specific request that failed and caused the bounce. – Chris Schaller Jul 17 '20 at 02:17
  • Look at the response from the OPTIONS request, look for an allow origin that matches your calling site. If this is not there, look for other conflicting config in your API – Chris Schaller Jul 17 '20 at 02:25
  • Please update the tag to reflect if this is ASP.Net or core? – Chris Schaller Jul 17 '20 at 02:32
  • @ChrisSchaller thanks for your questions. This is now resolved so unfortunately I cannot reproduce the traces. However the issue was due to a malformed body in the request. – dylanT Jul 17 '20 at 04:41

3 Answers3

1

Your CORS configuration looks correct, if some requests work, but not others then there is potential that the issue is not at the API end at all.

  1. In the API startup.cs, make sure that CORS is configured before all other configurations.

    app.UseCors(builder => builder
       .AllowAnyOrigin()
       .AllowAnyMethod()
       .AllowAnyHeader()
    

    This code is valid, though not very secure, it will satisfy browser CORS protocols globally for your app

  2. Make sure that throughout your API there is no conflicting CORS config, look for individual CORS config on the controllers or methods for the request that is failing.

  3. Check the client end, although your client code looks OK, the body is injected from a variable, to troubleshoot any client to server issues you need to either log the full request in plain text, or retrieve it from the network traffic inspection tools in your web browser at runtime.

    If most queries to your API resolve correctly and it is only one or two that fail, this is a good indicator that there is a problem at the client end, you should probably start here.


Update:

OP's issue was not directly related to CORS at all, it is however a good reminder of two important lessons:

  1. Malformed requests the Web API may fail before generating the correct response to an OPTIONS request, and if the OPTIONS request does not respond according to spec, the browser will report this as a CORS denial issue first, supressing the real erroneous response from the API

  2. In posting issues to forums for advice on resolving errors, providing code that causes errors only paints part of the picture. You need to include logs that show the runtime values as well as the actual error message.

  • For debugging any Web API issues between client and server, you should always look at the actual HTTP Request and Response content and headers for the affected call, you can see the network trace using your browser dev tools, however if you need to regularly debug issues like this in production you should consider request trace logging either at the client or the server side.
Chris Schaller
  • 6,580
  • 3
  • 34
  • 56
  • I don't believe this would work as you aren't supposed to combine AllowAnyOrigin with AllowCredentials. – dylanT Jul 17 '20 at 04:35
  • 1
    Thanks @dylanT you are not supposed to, but that doesn't mean you can't. The key here that I overlooked is that it only fails on one specific request. I assumed that this was the only request where you used authentication, but that was a silly assumption to make. I have totally changed my response now, but its good to remember that this is a common scenario in web api and client development. Don't just look at CORS as the problem simply because that's what the browser _thinks_ is the issue. – Chris Schaller Jul 18 '20 at 04:47
  • 1
    Thanks for the detailed update. I'll mark your answer as correct as it has some useful tips. – dylanT Jul 20 '20 at 12:35
0

You cannot combine 'allow any origin' with authorization. It's a security risk. Rather than allowing any origin, you can echo back the origin of the request, though you should be aware that doing is so brings some security risk - you're allowing auth tokens from any domain. It's better to configure CORS properly with the allowed domains.

Please see the accepted answer for this question: C# WEB API CORS does not work for one way to configure the backend in this scenario, avoiding the use of Access-Control-Allow-Origin:*.

see sharper
  • 8,591
  • 5
  • 29
  • 51
  • I appreciate that. I am just trying to get it to work in the simplest case. Do you think that the allow any origin is what is causing the error? – dylanT Jul 17 '20 at 01:48
  • This really doesn't address OP's issue at all – Chris Schaller Jul 17 '20 at 02:15
  • @dylanT Yes. I am not just telling you about the security risk. I am saying the browser won't allow it. – see sharper Jul 17 '20 at 02:21
  • @ChrisSchaller ? Browsers won't allow credentialled requests with allow any origin. – see sharper Jul 17 '20 at 02:22
  • @seesharper In code we say "Allow Any" but the implementation at runtime actually returns the caller host, not "*", OPs code should be doing this correctly, as long as there is not any conflicting config – Chris Schaller Jul 17 '20 at 02:27
  • Are you sure @ChrisSchaller? I see this in the docs: `Specifying AllowAnyOrigin and AllowCredentials is an insecure configuration and can result in cross-site request forgery. The CORS service returns an invalid CORS response when an app is configured with both methods.` – see sharper Jul 17 '20 at 02:36
  • Regarding: https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#set-the-allowed-origins this might be true for [asp.net-core] but works fine in .Net FX, I haven't noticed any issues in my APIs but when we deploy to live hosts we configure the explicit origins. – Chris Schaller Jul 17 '20 at 02:56
0

After much troubleshooting, we were able to determine that the root cause of the issue was the body of the request. The stringify method was embedding double-quotes inside a string that was enclosed in double-quotes.

Why this caused a CORS error remains unclear to me, but it is likely a red herring.

Fixing the body resolved the issue.

I would be interested to understand the chain of events that led to a CORS error in the browser. But otherwise we have now resolved this.

dylanT
  • 942
  • 1
  • 8
  • 24