Two calls on Post request: with http 204 and 200 - asp.net-core

I have implemented Cors policy in dot net core application:
In Startup.cs under ConfigureServices I have added the following cors policy
services.AddCors(options =>{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
I'm facing a strange issue after adding CORS policy, on every POST call from UI there are two calls made: first calls returns with 204 and other call returns the data with 200 status code.

First one is a preflighted request. The main goal is to determinate whether the actual request is safe to send. Cross-site requests are preflighted since they may have implications to user data.
A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood.
It is an OPTIONS request using two HTTP request headers: Access-Control-Request-Method and Access-Control-Request-Headers, and the Origin header.
A preflight request is automatically issued by a browser when needed.
This HTTP access control (CORS) describe conditions that if true then request is preflighted.

Related

Retrieving http response headers information from any website

I'm using Vue CLI and axios.
I have a searchbar where the user can input (potentially) any website and read info about the HTTP request and response.
Some of the information I need to get are: HTTP protocol, Status code, Location (if redirected), Date and Server.
What I'm doing is a simple axios GET request taking the input from the searchbar.
I'm trying to get my head around the CORS domain issues, but even then, when I input a CORS supported site like myjson I can access only the CORS-safelisted response headers which are not what I'm looking for.
This is the axios call:
axios
.get(url)
.then((r) => {
console.log(r);
console.log(r.headers.server); //undefined
})
.catch((e) => {
console.error(e);
});
Is the brief I'm presenting even possible?
UPDATE
I've then tried removing the chrome extension I used to enable CORS requests and installed Moesif Origin & CORS Changer extension. After restarting my PC I have now access to the remaining response headers.
I don't really know exactly what went wrong with the previous extension, but hopefully this helps somebody.
It's also worth pointing out that at the current date I'm writing this edit, myjson site has been flagged by chrome as non-safe for privacy issues. I've simply made HTTP requests to other sites and got the response headers as described.
The response to a cross-origin request for https://myjson.dit.upm.es/about contains the CORS-related headers
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, PATCH, PUT, DELETE, POST, OPTIONS
but no Access-Control-Expose-Headers. Without that, a cross-origin client cannot access the Server header, because it is not CORS-safelisted.
It would work if you had your server make the request and evaluate the headers, not the axios client.

how to skip Preflight Requset in vue with content-type:application/json

error :"405 not allowed Method" in post method type call in request command vue
i need call api function with content-type:application/json and post Method type with request command in vue ,but browser add preflight request with options method type and it causes this error :"405 not allowed Method"
var options = {
method: "POST",
url: "http://api.sample.com/login",
headers: {
"Access-Control-Request-Method":"POST",
"cache-control": "no-cache",
"content-type": "application/json",
},
body: '{ Username: "demo", Password: "demo", Domain: "test" }'
};
request(options, function(error, response, body) {
if (error) throw new Error(error);
body.data;
alert("ok");
});
The OPTIONS call is done whenever you do a cross-origin request. This means the domain your application is running on is different from the domain where the api is. A pre-flight request is mandatory for these requests, because the browser needs to figure out if you are allowed to do these requests. A 405 error means that the server thinks you are not allowed to make that request.
To solve this problem you can move your api to the same domain as your frontend. Please note that it cannot be on a subdomain.
A different way of solving this, is by sending back the correct headers. In your case you seem to at least miss the Access-Control-Allow-Methods response header. Make sure to send this header and either dynamically figure out which methods are allowed, or do something like the following. That would allow the most common methods to work.
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
In the comments you said that you do not have control over the api, and as such cannot change the response header. In that case your best bet is to contact whoever maintains the api and ask how to best use their api.
In the comments you said that this worked fine when you did the same thing in ASP.NET. ASP.NET is a server-side language, which means that requests in that context do not have a concept of "cross-origin". Cross-origin only comes into play in the browser, where the application runs on an actual domain.
Assuming you can set up a proxy on your application domain, you can also create a proxy that proxies all requests to the api you actually want to communicate with. You would deploy your domain on https://example.com and do your requests to https://example.com/api/endpoint. Your proxy will listen for requests that begin with https://example.com/api and proxy it to https://whatever.the.api.is/ with the appropriate endpoint and data.
Please keep in mind that while some api's might just be configured incorrectly, a lack of cross-origin response headers might just mean that the api is nog meant to be consumed through the browser. Part of this could be that the request contains a secret that should not be exposed to users that use your application, but should instead only be on the server. Using a proxy in that case would set you up for impersonation attacks, because you would expose the secret to your application, but defeat the cross-origin headers by making it appear to the application that the api is on the same domain.

Asp.net Core allow custom headers with CORS (with axios on client side)

I have an single app (in Vuejs) + axios on client side and Asp.net Core Web Api server side.
I have add a jwt token auth. I have configured my server to add a custom header when the token is expired. (I had "Token-Expired" header in the response).
The header "token-expired" was not present in error.response.headers object from axios interceptor ... (Note: It is frustrating because the header is present on Postman but not with axios).
Edit: This issue on github seems similary to my case https://github.com/axios/axios/issues/606
By default, the browser doesn't expose all of the response headers to the app. For more information, see W3C Cross-Origin Resource Sharing (Terminology): Simple Response Header.
The response headers that are available by default are:
Cache-Control
Content-Language
Content-Type
Expires Last-Modified
Pragma
Source: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2#set-the-exposed-response-headers
More general info: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2
To make other headers available to the app, call WithExposedHeaders method in the Configure from startup.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseCors(builder =>
{
builder.WithOrigins("http://localhost:8080");
builder.AllowAnyHeader();
builder.WithExposedHeaders("Token-Expired");
builder.AllowAnyMethod();
builder.AllowCredentials();
builder.Build();
});
}
Note: You must set an specific origin (and not add AllowAnyOrigin() method).
Indeed, The CORS specification also states that setting origins to "*" (all origins) is invalid if the Access-Control-Allow-Credentials header is present.
Et voilĂ  :)

Cannot make cross origin request between local ASP.NET Core MVC services

I have two applications running locally. one is a web service at https://localhost:44365, the other is a web application at https://localhost:44360. The web application needs to access the web service.
The web service is set up with a cors policy that should allow this:
// For running on local pc
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
...
app.UseCors("CorsPolicy");
app.useMvc();
...
}
When I run both applications and hit the web application in my browser, I get cross origin errors:
Failed to load https://localhost:44365/api/users/current/avatarText: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:44360' is therefore not allowed access. The response had HTTP status code 500.
The headers in from the service (at 44365) were:
access-control-allow-credentials: true
access-control-allow-headers: content-type
access-control-allow-origin: https://localhost:44360
Oddly, I also show a 500 server error in the method in question. Although when the application (44360) calls it, I am able to step through the method (in 44365) and there is no 500 within that method. I can call it successfully when the call is not cross origin.
You should use AllowAllOrigins
options.AddPolicy("AllowAllOrigins",
builder =>
{
builder.AllowAnyOrigin();
});
Source: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1#set-the-allowed-origins
Consider carefully before allowing requests from any origin. Allowing requests from any origin means that any website can make cross-origin requests to your app.
This setting affects preflight requests and the
Access-Control-Allow-Origin header (described later in this topic).

AngularJS trying to do CORS

I have a Ruby On rails Json API. I also have an AngularJS frontend and I am making CORS requests.
Everything works ok when I return 200 (for example on posts it's actually calling OPTIONS method and getting cors headers for the server). But when I return 401 (unauthorized) I get a Cross site error. I want to handle this error and show an appropiate message (when the user is not authorized to execute a method) but it seems that 401 response fires CORS error.
Any help?
CORS is independent of authentication. Your should layer your CORS response on top of your actual response. So in the case of an authentication error, here's how you should respond:
The preflight response (e.g. the response to the OPTIONS request) should always return HTTP 200, along with the appropriate CORS headers: Access-Control-Allow-Origin, Access-Control-Allow-Methods and Access-Control-Allow-Headers (if necessary). There should be no body on the preflight response.
The actual response should respond with 401, if there is an auth error. But it should still have the CORS headers, e.g. Access-Control-Allow-Origin etc.
This tells the browser that the cross-origin request was successful, but there was an underlying issue with the request (e.g. the auth error).