PLEASE READ THROUGH EDIT 4+ AS THAT IS THE LATEST ON THIS ISSUE
So I've got an API in C# which has auth set up in the web.config. It redirects to another project which handles the authentication. When a request is made it checks if the user is logged in within Login.aspx. I've set up the CORS policy to allow requests by changing the WebApiConfig.cs file to:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var cors = new EnableCorsAttribute("http://localhost:1337", "*", "*");
config.EnableCors(cors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I've also allowed all pre-flight requests to be ignored by putting this into the Global.asax.cs. I was getting an error before which is why I had added this:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OrdinalIgnoreCase) &&
Request.HttpMethod == "OPTIONS")
{
Response.Flush();
}
}
Now when I make a request from my React app to the API I get the following error:
Access to fetch at 'http://localhost:9074/Login.aspx' (redirected from 'http://localhost:9074/Customer/GetAll/') from origin 'http://localhost:1337' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
I don't understand why the pre-flight request isn't being flushed. I want it to go to the login.aspx page on the API realise it's not logged in and see that the origin header isn't the same as the API uri so it'll send back a json response which will include the url for the user to use to authenticate. Then on the react app I can just redirect the user to that url.
If someone was accessing from the API directly (ie they were to visit http://localhost:9074/Customer/GetAll/) then it would just redirect the user instead to the login page to be authenticated. That way react shouldn't complain about a fetch request being redirected to an external page since it's actually getting a value returned (the url).
I can see that it hits the global.asax.cs twice once with a http Method Options which gets flushed and then the second with a Get http Method. When I click on Step Over it doesn't run anything else (I've got a breakpoint on login.aspx) and just gives the error above.
EDIT 1
Changing the Content-Type as suggested here also doesn't help. Regardless of the Content-Type it still sends a pre-flight request. Whenever I get information directly from the API ie I visit (localhost:9072/Customer/GetAll) I don't hit the breakpoint in global.asax.cs
EDIT 2
I've also come across this (Check the second section). Although changing the Content-Type from application/json to something else didn't work I'm assuming it still sends the pre-flight request since it's got Authorization. Since the login.aspx page doesn't expect a GET request is that why it returns a http error 405 Method Not Allowed? My login.aspx page is what checks whether the user is authenticated and redirects them to the login page (a separate external project). Is there a way to ignore the pre-flight request while still keeping authentication enabled as in the solution linked they advised removing it so that you wouldn't get the error.
NETWORK TAB
EDIT 3
When I had opened the terminal and ran curl -X OPTIONS http://localhost:9074/login.aspx -i I had gotten:
HTTP/1.1 405 Method Not Allowed
Cache-Control: private
Allow: GET, HEAD, OPTIONS, TRACE
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcbW5hemlyXERlc2t0b3BcQWZ0b25cUnVsZXMgRW5naW5lXFJ1bGVFbmdpbmVBUEkgLSBDb3B5XFJ1bGVFbmdpbmVBUElcbG9naW4uYXNweA==?=
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: GET,POST,OPTIONS,DELETE,PUT
Date: Tue, 25 Oct 2022 13:44:56 GMT
Content-Length: 5288
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>IIS 10.0 Detailed Error - 405.0 - Method Not Allowed</title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana,Arial,Helvetica,sans-serif;}
code{margin:0;color:#006600;font-size:1.1em;font-weight:bold;}
.config_source code{font-size:.8em;color:#000000;}
pre{margin:0;font-size:1.4em;word-wrap:break-word;}
ul,ol{margin:10px 0 10px 5px;}
ul.first,ol.first{margin-top:5px;}
fieldset{padding:0 15px 10px 15px;word-break:break-all;}
.summary-container fieldset{padding-bottom:5px;margin-top:4px;}
legend.no-expand-all{padding:2px 15px 4px 10px;margin:0 0 0 -12px;}
legend{color:#333333;;margin:4px 0 8px -12px;_margin-top:0px;
font-weight:bold;font-size:1em;}
a:link,a:visited{color:#007EFF;font-weight:bold;}
a:hover{text-decoration:none;}
h1{font-size:2.4em;margin:0;color:#FFF;}
h2{font-size:1.7em;margin:0;color:#CC0000;}
h3{font-size:1.4em;margin:10px 0 0 0;color:#CC0000;}
h4{font-size:1.2em;margin:10px 0 5px 0;
}#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS",Verdana,sans-serif;
color:#FFF;background-color:#5C87B2;
}#content{margin:0 0 0 2%;position:relative;}
.summary-container,.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
.content-container p{margin:0 0 10px 0;
}#details-left{width:35%;float:left;margin-right:2%;
}#details-right{width:63%;float:left;overflow:hidden;
}#server_version{width:96%;_height:1px;min-height:1px;margin:0 0 5px 0;padding:11px 2% 8px 2%;color:#FFFFFF;
background-color:#5A7FA5;border-bottom:1px solid #C1CFDD;border-top:1px solid #4A6C8E;font-weight:normal;
font-size:1em;color:#FFF;text-align:right;
}#server_version p{margin:5px 0;}
table{margin:4px 0 4px 0;width:100%;border:none;}
td,th{vertical-align:top;padding:3px 0;text-align:left;font-weight:normal;border:none;}
th{width:30%;text-align:right;padding-right:2%;font-weight:bold;}
thead th{background-color:#ebebeb;width:25%;
}#details-right th{width:20%;}
table tr.alt td,table tr.alt th{}
.highlight-code{color:#CC0000;font-weight:bold;font-style:italic;}
.clear{clear:both;}
.preferred{padding:0 5px 2px 5px;font-weight:normal;background:#006633;color:#FFF;font-size:.8em;}
-->
</style>
</head>
<body>
<div id="content">
<div class="content-container">
<h3>HTTP Error 405.0 - Method Not Allowed</h3>
<h4>The page you are looking for cannot be displayed because an invalid method (HTTP verb) is being used.</h4>
</div>
<div class="content-container">
<fieldset><h4>Most likely causes:</h4>
<ul> <li>The request sent to the Web server used an HTTP verb that is not allowed by the module configured to handle the request.</li> <li>A request was sent to the server that contained an invalid HTTP verb.</li> <li>The request is for static content and contains an HTTP verb other than GET or HEAD.</li> <li>A request was sent to a virtual directory using the HTTP verb POST and the default document is a static file that does not support HTTP verbs other than GET or HEAD.</li> </ul>
</fieldset>
</div>
<div class="content-container">
<fieldset><h4>Things you can try:</h4>
<ul> <li>Verify the list of verbs enabled for the module handler this request was sent to, and ensure that this verb should be allowed for the Web site.</li> <li>Check the IIS log file to see which verb is not allowed for the request.</li> <li>Check the failed request tracing logs for additional information about this error. For more information, click <a href="http://go.microsoft.com/fwlink/?LinkID=66439">here</a>. </li> </ul>
</fieldset>
</div>
<div class="content-container">
<fieldset><h4>Detailed Error Information:</h4>
<div id="details-left">
<table border="0" cellpadding="0" cellspacing="0">
<tr class="alt"><th>Module</th><td> StaticFileModule</td></tr>
<tr><th>Notification</th><td> ExecuteRequestHandler</td></tr>
<tr class="alt"><th>Handler</th><td> StaticFile</td></tr>
<tr><th>Error Code</th><td> 0x80070001</td></tr>
</table>
</div>
<div id="details-right">
<table border="0" cellpadding="0" cellspacing="0">
<tr class="alt"><th>Requested URL</th><td> http://localhost:9074/login.aspx</td></tr>
<tr><th>Physical Path</th><td> C:\Users\...\API\login.aspx</td></tr>
<tr class="alt"><th>Logon Method</th><td> Anonymous</td></tr>
<tr><th>Logon User</th><td> Anonymous</td></tr>
</table>
<div class="clear"></div>
</div>
</fieldset>
</div>
<div class="content-container">
<fieldset><h4>More Information:</h4>
This error means that the request sent to the Web server contained an HTTP verb that is not allowed by the configured module handler for the request.
<p><a href="https://go.microsoft.com/fwlink/?LinkID=62293&IIS70Error=405,0,0x80070001,19044">View more information »</a></p>
</fieldset>
</div>
</div>
</body>
</html>
however when I ran curl -X GET http://localhost:9074/login.aspx -i I got what I was expecting ie the login.aspx page had ran. I feel like I'm getting closer to the solution now :D
EDIT 4
What I think the issue is, is that the API can't handle http OPTIONS methods. I had put into global.asax.cs:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OrdinalIgnoreCase) &&
Request.HttpMethod == "OPTIONS")
{
Response.Flush();
}
}
so when I first go to /GetAll it sends first a OPTIONS request where the response gets flushed and then a GET request which tries to retrieve the data. Without authentication this work fine. Since I've got authentication before retrieving the data from \GetAll it redirects the page to Login.aspx to see if the user is authenticated because of the redirect it tries to send the OPTIONS request again. Since it's not a new request it doesn't run Application_BeginRequest() so the OPTIONS request doesn't get flushed. Flushing the OPTIONS request was a work around for the issue of it returning HTTP Statuses 405 (this was before I had implemented the authentication) but as it's a redirect then it doesn't flush the OPTIONS request and just returns 405 so the GET request doesn't get sent since it's expecting a http status 2XX. How do I properly handle the OPTIONS request? Is there something like Application_BeginRedirect where I can flush the OPTIONS request like I did properly? Would this be inappropriate?
