Using Fetch api DELETE method with no-cors enabled - javascript

I am trying to make an API requests that deletes an entity in the backend. My spring server and node.js server are running on different ports.
When I try a fetch request with cors enabled (mode: "cors") I get an error that the request was blocked by the cors policy. When I disabel cors (mode: "no-cors"), I get the following error:
Failed to execute 'fetch' on 'Window': 'DELETE' is unsupported in no-cors mode.
The code for the request:
export async function deleteOneProcessType(id) {
let ret = await fetch(`${restUri}${uri}/${id}`, {
method: "DELETE",
mode: "no-cors"
})
}
I have similar POST and GET methods whith cors disabled that work just fine.

No need to set mode: "no-cors"
Indeed you just need toadjust your backend in order to allow your request
To do so add a WebMvcConfigurer Bean
You can do so using a Configuration class for instance.
You can refer to https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
As mentionned in the documentation by default only GET and POST requests are allowed.
Then you need to allow DELETE as well
Finally you should have something like that :
#Bean
public WebMvcConfigurer corsController()
{
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("[Your_backend_server_URI_here]/**")
.allowedOrigins("[Your_frontend_URL_here]")
.allowedMethods("PUT","DELETE","GET","POST");
}
};
}

POST and GET are considered simple requests where you can use mode: "no-cors" . You cannot do this with DELETE and PUT for example. I suggest you to use Proxy server for all your API calls. With a Proxy server you can solve CORS error.
Example: you want to delete an entity to this api: https://test.api.com/customer/1.
In package.json add the following line:
"proxy": "https://test.api.com"
Your request in the component:
export async function deleteOneProcessType(id) {
let ret = await fetch(`/customer/${id}`, {
method: "DELETE"
})

Related

CORS issue while getting access token using client_credentials using javascript/reactjs from microsoft graph /token?

I need to get the access token using fetch() method but i am unable to do so with the fetch() method. Tried allowinng Cors-policy or cross-Access-Origin to all but nothing seems to working.
Access to fetch at 'https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxx/common/oauth2/v2.0/token' from origin 'http://localhost:3050' 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.
graphService.ts:81 POST https://login.microsoftonline.com//common/oauth2/v2.0/token net::ERR_FAILED
Thanks in Advance:)
You are getting cors error because Azure AD rejects the request when you include Origin header while using client_credentials. To start with You are using the client_credentials flow the wrong way.
Consider reading through this guide on client credentials flow to help you understand why its preferred for server side / daemon applications.
To see the error just add Origin header to postman and do the request again.
Also read here to understand the oauth2 flows that you can use
For your case, you can use authorization code flow because you have an SPA.
It is not the flow or configuration that is causing the issue. The real issue is front-end or SPA. IF you want to call the API for getting token with client Credential flow,You must follow either of the two approaches that is a mandatory thing I guess.
1.Daemon Services
2.Server side Implementation
I have called the API with Node and with same configuration as mention in the docs its working fine now.
msal-node npm package is an alternate to call the api or you can call the graph api by yourself.
async getAppTokenFromAzureAD() : Promise <any | Error> {
const requestHeaders : HeadersInit = new Headers();
var details = {
'client_secret' : 'xxxxxxxxxxxxxxxxxxxxxx',
'client_id':'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'scope':'https://graph.microsoft.com/.default',
'grant_type':"client_credentials"
};
let formBody:any = [];
for (var property in details) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
requestHeaders.set('Content-Type', 'application/x-www-form-urlencoded');
requestHeaders.set('Host','login.microsoftonline.com');
return new Promise((resolve,reject)=>{
this.connection.transaction(async (entityManager) => {
try {
let tokenResponse = fetch('https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxx9/oauth2/v2.0/token',{
method : 'POST',
headers : requestHeaders,
body : formBody
})
tokenResponse.then(data=>data.json()).then(responses=>{
resolve({
statusMessage: getMessageByKey('apllicationTokenSuccess'),
responses,
})
}).catch(error=>{
reject(error);
})
} catch (error) {
reject(error)
}
})
})
}
Thanks

Ajax POST call blocked by CORS from ASP NET Web API - Response to preflight request doesn't pass access control check

Problem Summary:
I have two web projects that are hosted with different domains. When making ajax call to my Web API project I get the following:
Access to XMLHttpRequest at '' from origin '' 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.
First Project - Web API
My first project, which is ASP NET Web API (.Net Framework 4.8)
I enabled CORS globally for everyone just to make sure the tests pass correctly.
In my WebApiConfig file, I have the following line.
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
With using System.Web.Http.Cors; above.
My method has nothing special like attributes since we enabled CORS globally.
[RoutePrefix("api/Test")]
public class TestController : ApiController
{
[Route("RequestConnection")]
[HttpPost]
public IHttpActionResult RequestConnection(MasterOnRequestInputModel inputModel)
{
...some code logic here...
}
}
Second Project - JavaScript with AJAX request
My second projects want to call the mentioned method above in the Web API.
My ajax call looks in the following way:
$.ajax({
type: "POST",
url: myUrl,
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: {
'Body': body,
'Head': head,
'Width': width,
'Height': height
},
success: screencastControllerPostSuccess
});
In Chrome the request looks as follow:
What am I doing wrong?
Edit:
Answer
If you guys did, exactly what is written above, you should have absolutely no problems with CORS.
My problem was with the WAF our company is using. The WAF was denying my request due to it being a potential attack. And this is because I was sending HTML elements in the request body. Together with my system administrator colleagues, we fixed the issue.
So the interesting part is, that after my request is denied from the WAF it returns an error as if the problem is with CORS. That is because indeed the request is cross-domain, but the WAF generic response after denying a request doesn't have the Access-Control-Allow-Origin header.
Have a look at the WAF of www.asp-waf.com, you will find it quite easy to work with also finding issues like that are easy as you just register with the OnGuardAction event and you can see what and why it would be blocked by debugging it or sending it to the log.
we do this by using the base class FireWallBase like this
public class MyFireWall : FireWallBase
{
private readonly ILogger<MyFireWall> _logger;
private bool _agreeWithFirewall = true;
public MyFireWall(
//enable accessing AppConfig
IConfiguration configuration
//allow DI to provide interfaces to base class
, ILoggerFactory? loggerFactory = null, IMemoryCache? memoryCache = null
, IIncidentDatabase? incidentDatabase = null, IWhoisRepository? whoisRepository = null, ISubscriptionsRepository? subscriptions = null
, IEmailReportDesination? emailReportDesination = null, IDatabaseReportDestination? databaseReportDestination = null
, ILoggerReportDesination? loggerReportDestination = null, IFireWallDiskLoggerDestination? diskLoggerDestination = null
, IEventLogReporting? eventLogReporting = null, IGeoFactory? geoFactory = null, ILatLongRepository? latLongRepository = null
, IResetRepository? resetRepository = null)
: base(loggerFactory, memoryCache, incidentDatabase, whoisRepository, subscriptions, emailReportDesination, databaseReportDestination
, loggerReportDestination, diskLoggerDestination, eventLogReporting, geoFactory, latLongRepository, resetRepository)
{
var section = configuration.GetSection("FireWall");
if (section.Exists())
{
_isReccommendOnly = section.GetValue<bool>("AgreeWithFirewall");
}
base.Trigger_OnFireWallCreated(this);
OnIncident += MyFireWall_OnIncident;
OnGuardAction += MyFireWall_OnGuardAction;
OnUserTypeChange += MyFireWall_OnUserTypeChange;
_logger = loggerFactory.CreateLogger<MyFireWall>();
}
private void MyFireWall_OnUserTypeChange(object? sender, Walter.Web.FireWall.EventArguments.UserTypeChangedEventArgs e)
{
_logger?.LogCritical("{oldType} : {newType}\n {route}\n Rules:\n {data}"
, e.OriginalType
, e.NewType
, e.Rout
, string.Join("\n ", e.Rules)
);
//allow the change
e.Allow = true;
if (e.OriginalType.HasFlag(UserTypes.IsSearchEngine) && e.NewType.HasFlag(UserTypes.IsMalicious))
{
//remove the malicious flag from search engines to not prevent search engines from
//indexing the site
e.NewType &= ~UserTypes.IsMalicious;
}
}
private void MyFireWall_OnGuardAction(object? sender, Walter.Web.FireWall.EventArguments.GuardActionEventArgs e)
{
_logger?.LogCritical("{Method} {page} : {route}\n {action}:{RuleNr}\n Reasons:{Reason}\n {data}"
, e.Page.Method
, e.Page.OriginalUrl.AbsolutePath
, e.Page.FireWallRoute
, e.Action
, string.Join("\n ", e.Page.PageViolationStack.Select(s => s.ToString()))
);
//allow the firewall to block requests
e.Allow = _agreeWithFirewall;
}
private void MyFireWall_OnIncident(object? sender, Walter.Web.FireWall.EventArguments.FireWallIncidentEventArgs e)
{
_logger?.LogCritical("{Method} {page} : {route}\n {rule}:{RuleNr}\n Reasons:{Reason}\n {data}"
, e.Page.Method
, e.Page.OriginalUrl.AbsolutePath
, e.Page.FireWallRoute
, e.StackEntry.Rule
, e.StackEntry.RuleNr
, e.StackEntry.Reason
, string.Join("\n ", e.Data.Select(s => $"{s.Key}:{s.Value}"))
);
//allow the firewall to raise incidents
e.Allow = _agreeWithFirewall;
}
}
We enable the firewall like everything else in .net web applications via dependency injection. I can enable my own firewall class by using it like so:
services.AddFireWall<MyFireWall>("Token", "Key", new Uri(Configuration["domainUri"], UriKind.Absolute), options =>{
//add your options here
});
In the options, you can configure CORS under options.Rules.Headers but you can do lots more than that.
The firewall is in my NuGet package Walter.Web.FireWall.* There are lot's of add-ons like geography as well as reporting to SMTP timed using a timespan you you can get emails every day and not get flodded with mails when a user got blocked.

No Access Control Allow Origin IIS

I have follow this tutorial of angular 7 to make a CRUD functions. I publish the project into my IIS but I am having an error (Image)
Access to XMLHttpRequest at 'http://192.168.120.178:2030/Api/Employee/UpdateEmployeeDetails/' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I tried to add the header in Update Code to allow the CORS but its the same.
The error also applies to other functions (Save, Delete)
Angular Code
updateEmployee(employee: Employee): Observable<Employee> {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Access-Control-Allow-Credentials': "true",
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Origin': '*'
})
};
return this.http.put<Employee>(this.url + '/UpdateEmployeeDetails/',
employee, httpOptions);
}
API Code
[HttpPut]
[Route("UpdateEmployeeDetails")]
public IHttpActionResult PutEmaployeeMaster(EmployeeDetail employee)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try
{
EmployeeDetail objEmp = new EmployeeDetail();
objEmp = objEntity.EmployeeDetails.Find(employee.EmpId);
if (objEmp != null)
{
objEmp.EmpName = employee.EmpName;
objEmp.Address = employee.Address;
objEmp.EmailId = employee.EmailId;
objEmp.DateOfBirth = employee.DateOfBirth;
objEmp.Gender = employee.Gender;
objEmp.PinCode = employee.PinCode;
}
int i = this.objEntity.SaveChanges();
}
catch (Exception)
{
throw;
}
return Ok(employee);
}
But If im running my project using a localhost API its okay. But in publish (IIS) im getting the CORS error. I spent one whole day already but unfortunately I didn't see a solution to my problem.
TL;DR: You actually have the CORS headers in the wrong direction.
The API (server side) needs to be the one returning the CORS headers as a way of signaling to the browser that you expected whatever domain the Angular UI is being served on (client side) to call your API.
See this article from Mozilla about CORS
If you think about it, it doesn't make sense for the client side / browser to set these CORS headers, because the client side can easily be compromised by a bad actor (such as chrome plugin, foreign javascript, etc.), and if the client side was in charge of these CORS headers, it would be really easy to make them be what a hacker wants them to be. Instead, they need to come from the server side - hinted at by the Access-Control-* prefix. It's the server's way of whitelisting domains it expects the front end to access it from.
Another way to think about it would be that I couldn't create a website that directly hit Facebook's API's if they have their CORS headers restricted to only allow *.facebook.com because I don't own that domain. CORS are also a protection layer to prevent bad actors from being able to use your server side APIs and spoof your front end to capture people's data.
if it is .net core go in Startup.cs and serve both back-end and front-end with https and enable CORS
public void ConfigureServices(IServiceCollection services)
{
...
services.AddCors();
...
}
public void Configure(IApplicationBuilder app)
{
...
app.UseCors(builder =>
builder.WithOrigins("YOUR_FRONTEND_URL")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
...
}
Source
Web API 2 (Prior Core)
Install-Package Microsoft.AspNet.WebApi.Cors
App_Start\WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute(
origins: "YOUR_FRONTEND_URL",
headers: "*",
methods: "*");
config.EnableCors(cors);
...
}
More Information

Cors issue API not on same server

I'm using Web API 2. in my WebApiConfig, I have this.
private static void EnableCrossSiteRequests(HttpConfiguration config)
{
var origin = WebConfigurationManager.AppSettings["origin"];
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*");
config.EnableCors(cors);
}
Register Method
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
EnableCrossSiteRequests(config);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Filters.Add(new ErrorHandler());
}
From my understanding shouldn't that all I need to for this to work? It's worked on my dev computer when they are hosted together. But now one is on a web server and the API is on a different web server.
I'm getting - Origin ... not found in Access-Control-Allow-Origin header.
I have it set to allow all Origin. I've tried adding it in the web config , and other methods posted around Stack overflow. I don't understand why its being denied?
Front end is Angular, using Ngresource for requests.
If I use the Network Tab in chrome dev tools, the Response to the request is 200 OK, and nothing else happens after that. Been searching all day for solutions, nothing I've tried so far has worked.
Thank you.
From my understanding shouldn't that all I need to for this to work?
Nope. You should decorate the Web API controllers/actions that you would like to be calling cross domain with the [EnableCors] attribute:
[EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")]
public class MyController: ApiController
{
...
}
Here's a good read on this topic.

CORS issue with ASP.net Identity

I am working on an angular.js project with one of my friends, and we are running into a specific CORS (cross origin request) issue. The server is a Microsoft ASP.NET restful API, and I am using angular.js with Node.js.
We enabled CORS on the server side, and are able to get responses for everything else, accept the user login, which we are using ASP.NET Identity with. We always get the same error which I will post bellow, as well as the POST from the Client side. So basically my question is, does any one have an idea on how to fix this? Thanks!
XMLHttpRequest cannot load http://lectioserver.azurewebsites.net/api/v1/accounts/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost' is therefore not allowed access. The response had HTTP status code 400.
function login(username, password) {
var innerconfig = {
url: baseUrl + "/api/v1/accounts/login",
data: {
username: username,
password: password,
grant_type: "password"
},
method: "POST",
headers:
{
'Accept': 'text/json'
}
};
return $http(innerconfig).then(onSuccess, requestFailed);
function onSuccess(results) {
if (results && results.data) {
$rootScope.access_token = results.data.access_token;
return results.data;
}
return null;
}
}
Try to set the content-type in the headers, this might fix the issue
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
This usually happens because app that provides you token starts before CORS initiates.
Fixing it is very easy. You just need to go to IdentityConfig.cs and inside that there is function called as
public static ApplicationUserManager Create
(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
Insert this following line of code there
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
This will enable CORS for Token request.
But problem is when we do this other normal requests will start throwing error since we have granted access origin * twice. Once in identiy and other in cors.
if you run into this error use this if statement on cors code in identity config you just pasted.
if(context.Request.ContentType == "text/plain")

Categories

Resources