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.
Related
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.
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/
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
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");
I'm working on an Angular application but when I call my local API I have this error
Failed to load https://localhost:44358/api/try: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
And I have also this :
ERROR
HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: null, ok: false, …}
error
:
ProgressEvent
So I saw some solutions and I try this on my .Net Core API in the startup file
services.AddCors(options =>
{
options.AddPolicy("AnyOrigin", builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
But I have the same error ...
Can I have some help ?
Finally it work, I think I forget to build my .Net Core API
If you use Angular 6, Angular CLI supports Proxy Config which will proxy your backend API call. Please check the Docs.
https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md