All PUT Requests are blocked by CORS policy - c#

I got a .NET 5 API with some cors-policies.
This are my CORS-settings:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddMemoryCache();
services.AddCors(options =>
{
options.AddPolicy("cors",
builder => builder
.WithOrigins(
"http://localhost:4200",
"http://127.0.0.1:4200",
"http://rev-staging.myhost.ch")
.WithMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.AllowAnyHeader()
.AllowCredentials()
);
});
...
}
and of course app.UseCors("cors"); in Startup.Configure(IApplicationBuilder, WebHostEnvironment )
When I execute my methods on localhost, everything works.
As soon as I publish to api-rev-staging.myhost.ch and execute them on live-server, for all PUT-requests I get
Access to XMLHttpRequest at 'http://api-rev-staging.myhost.ch/api/v1/Vacancies/7' from origin 'http://rev-staging.myhost.ch' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
(I changed the URL because it's company URL)
All GET and POST requests do work - just the PUT-requests don't work. They neither work when executing from angular front-end on http://rev-staging.myhost.ch nor when executing from postman on my local machine - but the GET and POST still work.
Any idea what is wrong here?
Edit: maybe it's important. Backend runs on IIS, same server like frontend, just another hostname.

Try to check if your server accept PUT and DELETE for Web API.
Out of the box these verbs are disabled.
Some documentation here:
https://inthetechpit.com/2019/02/24/enable-put-and-delete-http-verbs-for-webapi-with-cors-on-iis-8-5/

Related

Securing Blazor WASM and API with Auth0. CORS Policy issue

I've been following the tutorial at Auth0 for securing a Blazor WASM and API with Aut0, which is found here --> https://auth0.com/blog/securing-blazor-webassembly-apps/
Securing the app works fine, but adding the API gives me issues. As soon as I add the authenticate attribute to the API Controller it results in this:
fetchdata:1 Access to fetch at
'https://localhost:7226/weatherforecast' from origin
'https://localhost:7298' 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.
I've added a policy to allow the app in the program.cs
builder.Services.AddCors(options =>
{
options.AddPolicy("Open", builder => builder.WithOrigins("https://localhost:7298").AllowAnyMethod().AllowAnyHeader());
});
I've played around with the program.cs and also added app.UseCors before authentication/authorization (as a provided solution I found online), which then results in another issue.
Failed to load resource: the server responded with a status of 401 ()
blazor.webassembly.js:1 crit:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: The input does not contain any JSON tokens. Expected the input to start with a valid JSON
token, when isFinalBlock is true. Path: $ | LineNumber: 0 |
BytePositionInLine: 0. System.Text.Json.JsonException: The input does
not contain any JSON tokens. Expected the input to start with a valid
JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 |
BytePositionInLine: 0.
That error seems to indicate an issue with the bearertoken not being set, but it is setup using BaseAddressAuthorizationMessageHandler.
builder.Services.AddHttpClient("APIClient", client =>
{
client.BaseAddress = new Uri("https://localhost:7226");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
I've added the project to GitHub, if more details on the code is of interest
https://github.com/obrungot/BlazorAuthenticationPlayGround.git
AddCors doesn't actually do anything except for adding a policy. It's not using that policy until you specify it somewhere. You can specify a global policy by using app.UseCors("Open"), add the policy to the endpoint routing e.g. app.MapGet("/test", () => Results.Ok("test")).RequireCors("Open") or for controllers by using an attribute like [EnableCors("Open")].
That you received a 401 suggested that Cors in general seems to work, however Cors also needs explicit permission to keep the Authorization header. This is done by adding "AllowCredentials()" to the policy like this:
builder.Services.AddCors(options =>
{
options.AddPolicy("Open", builder => builder
.WithOrigins("https://localhost:7298")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
I hope this helps!
Edit:
Sorry. I somehow missed the github repository link. The reason why it doesn't work is that BaseAddressAuthorizationMessageHandler is meant for hosting the API within the BaseAddress of the app. So in your case only calls to https://localhost:7298/ will include the token. You might either choose to host the API together with the app in the same process (this can be set up by choosing "ASP.NET Core Hosted" in the template) or use a custom AuthorizationMessageHandler which you can learn about here https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/additional-scenarios?view=aspnetcore-7.0#custom-authorizationmessagehandler-class
In your case this would look like this:
public class ApiAuthorizationMessageHandler : AuthorizationMessageHandler
{
public ApiAuthorizationMessageHandler(IAccessTokenProvider provider, NavigationManager navigationManager) : base(provider, navigationManager)
{
ConfigureHandler(new[] { "https://localhost:7226" });
}
}
When it comes to the cors the order is important
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
If set up like that "[EnableCors("Open")]" on the controller should work.

Getting CORS errors on HTTP Post call on frontend

I wrote an Asp.Net Core api and so far it has been working great, however when I try to send a post request it gives me Access to XMLHttpRequest at 'https://localhost:44339/api/drawing/checkout' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have CORS enabled on my backend(startup.cs) like so :
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:4200")
.AllowCredentials()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
and app.UseCors(MyAllowSpecificOrigins);
I've already wasted a couple of days on this, my GET requests work, as well as my POST requests using Insomnia. Could someone please help me with the Angular part? here's the code I have
On drawing.service.ts:
test(param) {
return this.http.post(this.url + '/checkout', param, {
headers: { 'Content-Type': 'application/json' },withCredentials:true
});
}
And on my component ts:
test() {
let stringfiedArray = JSON.stringify(this.viewerPerm);
console.log(stringfiedArray);
this.drawingSearchService.test(stringfiedArray).subscribe();
}
You need to create a proxy.conf.json file on your Angular project including the following content
{
"/api": {
"target": "http://localhost:4200",
"secure": false,
"changeOrigin": true,
"pathRewrite": {
"^/api": ""
}
}
}
Where you call the service you will reference the proxied api as follow:
this.http.get(`api/checkout`);
remember to use ` character and not single quotes.
When you run your application be sure to add the proxy file
ng serve --proxy-config proxy.conf.json
GUIDE
On the backend, for internal use only, try setting it as follow
services.AddCors(options =>
{
options.AddPolicy("AllowAnyOrigin",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
First, I am going to assume that your current code is working fine with another API service, and does POST requests just fine. I hope you have tested your front end code for sure, and have isolated the problem is only with your API server.
Second, instead of a named policy, try using default policy, just to see if that makes a difference. it would look like this.
//lets add some CORS stuff
services.AddCors(options =>
{
options.AddDefaultPolicy(builder => {
builder.WithOrigins("http://localhost:4200");
builder.AllowAnyMethod();
builder.AllowAnyHeader();
builder.AllowCredentials();
});
});
and later, in Configure,
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(); //it may not matter, but try to put cors between routing and auth.
app.UseAuthorization();
Access to XMLHttpRequest at 'https://localhost:44339/api/drawing/checkout' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
A CORS preflight request using the HTTP OPTIONS method is used to check whether the CORS protocol is understood and a server is aware using specific methods and headers.
And the OPTIONS requests are always anonymous, you mentioned that you enabled NTML authentication, which would cause server not correctly respond to the preflight request.
For more information about "CORS preflight request", please check: https://learn.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference#cors-preflight-request
If you'd like to run your app(s) on local for testing purpose with CORS, to fix this issue, you can try to enable anonymous authentification to allow anonymous access.
Besides, if you host your app(s) on IIS server, to fix this issue, you can install IIS CORS module and configure CORS for the app.

Enable preflight CORS between C# and Angular

I am trying to make CORS work for request that require a preflight check. In this case I am making a POST-request to the back-end with an extra header.
Angular:
let myHeaders = new HttpHeaders();
myHeaders = myHeaders.append('Content-Type', 'application/json');
return this.http.post<UserOrder>(`${this.apiURL}/Order/PlaceOrder`, JSON.stringify(payload), {headers : myHeaders}); //email);
C# API:
[HttpPost("PlaceOrder")]
public GenericResponse PlaceOrder(UserOrderInsertModel userOrder)
{
return _orderProvider.PlaceOrder(new UserOrder());
}
Because of the preflight check it first makes an OPTIONS-request. When I do not define a separate options-endpoint in the backend I get a 405 Method Not Allowed. This made me think I needed a separate options-endpoint in my back-end on top of the post-endpoint.
[HttpOptions("PlaceOrder")]
public ActionResult PlaceOrderOptions(UserOrderInsertModel userOrder)
{
return Ok();
}
After adding this I run into a 415 Unsupported Media Type (on the options call). This is probably because the Content-Type header is not supported for a HttpOptions request.
I feel like the extra options endpoint shouldt be neccessary at all. The CORS-middleware I currently use is as follows:
httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:4200");
httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "*");
httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
Extra info: the CORS in general did already work. Cross-site scripting with a GET request and the Access-Control-Allow-Origin header went well. It is just that I cannot get the POST/OPTIONS combo to work.
Edit: in the Startup.cs I first tried to use app.UseCors() as follows:
app.UseCors();
options => options.WithOrigins("http://localhost").AllowAnyMethod()
);
This unfortuantely didnt work so then I resorted to inserting the middleware as described above.
Any help would be highly appreciated!
Ok, thanks a lot everybody. The problem was most likely in the middleware I was using. This was a workaround I added because the UseCors() initially didnt work. This was probably because I didnt use app.AddCors() initially. Without the custom middleware it makes everything a lot easier!
A quick look at the documentation will clarify few things. I share few extracts below
Because of the preflight check it first makes an OPTIONS-request. When I do not define a separate options-endpoint in the backend I get a 405 Method Not Allowed. This made me think I needed a separate options-endpoint in my back-end on top of the post-endpoint.
Preflight Request
For some CORS requests, the browser sends an additional OPTIONS request before making the actual request. This request is called a preflight request.
The browser can skip the preflight request if all the following conditions are true
The request method is GET, HEAD, or POST.
The app doesn't set request headers other than Accept,
Accept-Language, Content-Language, Content-Type, or Last-Event-ID.
The Content-Type header, if set, has one of the following values:
application/x-www-form-urlencoded multipart/form-data text/plain
I feel like the extra options endpoint shouldt be neccessary at all.
Except you are using CORS with endpoint routing, ASPNET Core should respond to appropriate preflight request when core is enabled on startup.
Condition for Automatic preflight
When the CORS policy is applied either:
Globally by calling app.UseCors in Startup.Configure.
Using the [EnableCors] attribute.
ASP.NET Core responds to the preflight
OPTIONS request.
Enabling CORS on a per-endpoint basis using RequireCors currently does not support automatic preflight requests.
Enable Cors on Starup
In configure service
public void ConfigureServices(IServiceCollection services)
{
.
//other codes
.
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder => //check corsbuilder for additonal config
{
builder.WithOrigins("http://example.com",
"http://www.contoso.com;
});
});
.
//other codes
.
}
and in Configure method
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
.
//Other codes
.
app.UseCors();
.
//Other codes
.
}
full documentation here for 3.0 https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.0#ecors
Enables Cors and make sure to AllowAnyHeader and AllowAnyMethod
Using .Net Core
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.WithOrigins(Configuration.GetValue<string>("JwtConfig:corsWhiteListUrl"))
.AllowAnyHeader()
.AllowAnyMethod();
});
});
Make sure to call UseCors() before UseEndpoints().
Another hint: If you have credentials, the wildcard do not work as expected.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods

How to get rid of CORS in .net core 2.2?

I've updated my project to .net core 2.2 and it seems like CORS is making problems that weren't there in 2.1.
I'm running my app on this URL: http://*:5300
I've added this code in the Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddCors(options =>
options.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowCredentials()
.AllowAnyHeader();
}));
services.AddMvc();
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseCors(builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowCredentials()
.AllowAnyHeader();
});
app.UseAuthentication();
app.UseMvc();
}
This didn't work, so I've added on top of it the [EnableCors] attribute on my `BaseController" class:
[EnableCors]
[Authorize]
[Produces("application/json")]
[Route("api/[controller]")]
public class BaseController : Controller
{
}
But I'm still getting this CORS error:
Access to XMLHttpRequest at 'http://192.168.15.63:5301/api/permissions/UI' from origin 'http://192.168.15.63:5302' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
What else can I do in order to completely remove CORS?
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
You cannot use both AllowAnyOrigin and AllowCredentials when using ASP.NET Core to respond to a CORS request.
Access to XMLHttpRequest at 'http://192.168.15.63:5301/api/permissions/UI' from origin 'http://192.168.15.63:5302' has been blocked by CORS policy
This message shows that your server is listening on http://192.168.15.63:5301, but your client is making the request from http://192.168.15.63:5302. Since the port is different, these are different origins and therefore CORS protection is used.
To allow the request to succeed, update your ASP.NET CORS configuration code to something like the following:
builder.WithOrigins("http://192.168.15.63:5302")
.AllowAnyMethod()
.AllowCredentials()
.AllowAnyHeader();
This configures the origin of the client as being supported by CORS - you could, of course, add this as a configuration option to the application itself (using e.g. appsettings.json), if needed.
Aside:
As you've called AddCors and configured a named policy, there is no reason to configure the same policy in the call to UseCors - you can simply pass in the name of the policy you configured earlier with AddCors:
app.UseCors("MyPolicy");

React+ASP.NET.Core : No 'Access-Control-Allow-Origin' header is present on the requested resource

Actually this is not a duplication post,I know a part of the title asked many times in stackoverflow community, I read all posts, and answers, but I think my problem and technologies which I used are different.
First of all I should mention ASP.NET Core WEB/API is my back-end-app and Reactjs is my front Application.
I read about CORS and I found out I must enable CORS on ASP.NET App and put 'Access-Control-Allow-Origin':'*' on my request's header, but I still have the below error while I call an api:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8080' is therefore not allowed
access. The response had HTTP status code 500. If an opaque response
serves your needs, set the request's mode to 'no-cors' to fetch the
resource with CORS disabled.
This is my Startup.cs code related to CORS:
public void ConfigureServices(IServiceCollection services)
{
// other lines of code
services.AddCors(options =>
{
options.AddPolicy("AllowAll",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new CorsAuthorizationFilterFactory("AllowAll"));
});
// other lines of code
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseCors("AllowAll");
app.UseAuthentication();
app.UseMvc();
}
This is my react code:
function save(message) {
const requestOptions = {
method: 'POST',
mode: 'cors',
headers: { ...authHeader(),
'Content-Type': 'application/json',
'Access-Control-Allow-Origin':'*',
},
body: JSON.stringify(message)
};
return fetch(config.apiUrl + '/message/save', requestOptions).then(handleResponse, handleError);
}
Thanks for your responding.
I had a similar problem recently. In my case it started working when I added services.AddCors(); in my ConfigureServices method and this part of code
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
in my Configure method. Remember to add those BEFORE UseMvc() call in both cases.
After two difficult days finally I found out how can I fix my problem. Actually one of your comment was a nice clue for me.
#kirk-larkin said:
The response had HTTP status code 500 is key here. When there's an exception in your ASP.NET Core project, the CORS headers are cleared. You should try and find out why an exception is being thrown.
I traced my code many times, then i found out I forget to register a service which I used in my controller in Startup.cs.
I called these below code in Startup.cs and my problem solved.
services.AddScoped<IMessageService, MessageService>();
With ASP.NET Core 2.1, when the controller throws an exception, which results in an error 500, the CORS headers are not sent. This should be fixed in the next version but until then you could use a middleware to fix this.
see
https://github.com/aspnet/CORS/issues/90#issuecomment-348323102
https://github.com/aspnet/AspNetCore/issues/2378
https://github.com/aspnet/CORS/issues/46
Also note that with credentials you need to explicitly add WithOrigins with host and port since most browsers simply ignore it otherwise (see https://stackoverflow.com/a/19744754/2477619):
app.UseCors(builder =>
builder
.WithOrigins("http://localhost:4200")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
As said by #Siavash the fact that it is returning 500 may indicate there is an issue with the build. I was having this problem today as it was working fine on localhost but was failing when deployed.
To debug the error, find this line in your web.config file in the root of the IIS directory:
<aspNetCore processPath="dotnet" arguments=".\CarpetrightBackend.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
Change stdoutLogEnabled="false" to true and then you will be able to see the error in the log file generated.
In my case I forgot to incude some static csv files when deploying that the program needed to reference and return data from it.

Categories

Resources