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")
Related
From my React JS app , I need to fetch data from servers in other domains.
However, I am prevented by CORS policy and not able to fetch the data.
Let us assume that my React app is running on localhost:3000 during the development.
I want to make get/post call to another server running on http://myserver.com
The URL through which I want to fetch the data is http://ext-server.com/data/records?name=xyz
I have installed http-proxy-middleware thru npm and using it in my react app.
Created a setupProxy.js file under src folder with below content :
const { createProxyMiddleware} = require("http-proxy-middleware")
module.exports = app => {
app.use(
createProxyMiddleware('/data/records' , {
target:'http://ext-server.com',
changeOrigin: true
})
)
}
On the landing page of my react app (firstpage.js) when http://localhost:3000 is hit , I have added below piece of code to the button event that makes the get call to the http://ext-server.com
getTheData() {
let url = "http://ext-server.com/data/records?name=" + encodeURIComponent(this.state.name);
axios.get(url,
{
headers: {
"Content-Type":"application/json;charset=UTL-8",
"Access-Control-Allow-Origin": "*",
Accept: "application/json",
},
baseURL: 'http://ext-server.com'
}
).then((response) => {
console.log(response["access_token"]);
}).catch(error) => {
console.log("Error: ", error)
}).then(function () {
console.log("always call it")
});
}
In the package.json , I have added :
"proxy": "http://ext-server.com",
"homepage":"http://localhost:3000",
But I am still getting below error:
Access to XMLHttpRequest at 'http://ext-server.com/data/records?name= ' from origin 'http://localhost:3000' has been blocked by CORS policy.
Is there anything that I am missing here ? what is the correct way to use this http-proxy-middleware?
Any help will be very useful!
Thanks
As you can see from MDN the "Access-Control-Allow-Origin": "*" header is a response type header, this means that it should go to in your server response. Also I advise you to not use the * symbol, instead I would rather match it with the origin header in your Request.
The CORS policy is one and only administered by the web server and its settings. To allow CORS requests it has to be implemented on server side. No chance to do it from your client application.
Basically its just a header setting (below example for NodeJS):
res.header("Access-Control-Allow-Origin", "*")
Sending that header will allow requests from every domain.
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
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
I am building a simple REST API using ktor and used cors but when i send a simple get request with no headers data the server works fine but if i want the client to have say key:1 the server doesn`t respond me correctly, it says the problem is
Failed to load http://127.0.0.1:8080/test: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 403.
so here is my ktor code
install(ContentNegotiation) {
gson {
}
}
install(ForwardedHeaderSupport)
install(DefaultHeaders)
install(CORS)
{
method(HttpMethod.Options)
method(HttpMethod.Get)
method(HttpMethod.Post)
method(HttpMethod.Put)
method(HttpMethod.Delete)
method(HttpMethod.Patch)
header(HttpHeaders.AccessControlAllowHeaders)
header(HttpHeaders.ContentType)
header(HttpHeaders.AccessControlAllowOrigin)
allowCredentials = true
anyHost()
maxAge = Duration.ofDays(1)
}
...
get("test"){
val a = call.request.headers["key"]
println(a)
call.respond(Product(name = a))
}
and my javascript code looks like this....
fetch('http://shop-ix.uz:8080/test', {
headers: {
"key": "1"
})
.then(response => response.json())
.then(json => {
console.log(json);
})
please help me
You need to whitelist your headers like this:
install(CORS) {
header("key")
}
This needs to be done with every custom HTTP header you intend to use.
Make sure all the headers and required methods should be allowed during Ktor CORS installation. I was facing the same issue, then I realized that I didn't add allowHeader(HttpHeaders.AccessControlAllowOrigin)
Although in the request header it was present. Because of that I am getting forbidden error (403)!
My Request Header!
Axios({
method: 'GET',
url: 'http://127.0.0.1:8080/connect',
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json",
},
params: {
...
}
})
Allowing CORS
install(CORS) {
allowMethod(HttpMethod.Options)
allowMethod(HttpMethod.Post)
allowMethod(HttpMethod.Get)
allowHeader(HttpHeaders.AccessControlAllowOrigin)
allowHeader(HttpHeaders.ContentType)
anyHost()
}
Check that what your request header wants is allowed on the server during CORS.
install(CORS) {
exposeHeader("key")
}
difference between header and exposeHeader - first allow to make call with this header, but second allow to use it on client side
I am working on an internal web application at work. In IE10 the requests work fine, but in Chrome all the AJAX requests (which there are many) are sent using OPTIONS instead of whatever defined method I give it. Technically my requests are "cross domain." The site is served on localhost:6120 and the service I'm making AJAX requests to is on 57124. This closed jquery bug defines the issue, but not a real fix.
What can I do to use the proper http method in ajax requests?
Edit:
This is in the document load of every page:
jQuery.support.cors = true;
And every AJAX is built similarly:
var url = 'http://localhost:57124/My/Rest/Call';
$.ajax({
url: url,
dataType: "json",
data: json,
async: true,
cache: false,
timeout: 30000,
headers: { "x-li-format": "json", "X-UserName": userName },
success: function (data) {
// my success stuff
},
error: function (request, status, error) {
// my error stuff
},
type: "POST"
});
Chrome is preflighting the request to look for CORS headers. If the request is acceptable, it will then send the real request. If you're doing this cross-domain, you will simply have to deal with it or else find a way to make the request non-cross-domain. This is why the jQuery bug was closed as won't-fix. This is by design.
Unlike simple requests (discussed above), "preflighted" requests first
send an HTTP request by the OPTIONS method to the resource on the
other domain, in order to determine whether the actual request is safe
to send. Cross-site requests are preflighted like this since they may
have implications to user data. In particular, a request is
preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
Based on the fact that the request isn't sent on the default port 80/443 this Ajax call is automatically considered a cross-origin resource (CORS) request, which in other words means that the request automatically issues an OPTIONS request which checks for CORS headers on the server's/servlet's side.
This happens even if you set
crossOrigin: false;
or even if you ommit it.
The reason is simply that localhost != localhost:57124. Try sending it only to localhost without the port - it will fail, because the requested target won't be reachable, however notice that if the domain names are equal the request is sent without the OPTIONS request before POST.
I agree with Kevin B, the bug report says it all. It sounds like you are trying to make cross-domain ajax calls. If you're not familiar with the same origin policy you can start here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript.
If this is not intended to be a cross-domain ajax call, try making your target url relative and see if the problem goes away. If you're really desperate look into the JSONP, but beware, mayhem lurks. There really isn't much more we can do to help you.
If it is possible pass the params through regular GET/POST with a different name and let your server side code handles it.
I had a similar issue with my own proxy to bypass CORS and I got the same error of POST->OPTION in Chrome. It was the Authorization header in my case ("x-li-format" and "X-UserName" here in your case.) I ended up passing it in a dummy format (e.g. AuthorizatinJack in GET) and I changed the code for my proxy to turn that into a header when making the call to the destination. Here it is in PHP:
if (isset($_GET['AuthorizationJack'])) {
$request_headers[] = "Authorization: Basic ".$_GET['AuthorizationJack'];
}
In my case I'm calling an API hosted by AWS (API Gateway). The error happened when I tried to call the API from a domain other than the API own domain. Since I'm the API owner I enabled CORS for the test environment, as described in the Amazon Documentation.
In production this error will not happen, since the request and the api will be in the same domain.
I hope it helps!
As answered by #Dark Falcon, I simply dealt with it.
In my case, I am using node.js server, and creating a session if it does not exist. Since the OPTIONS method does not have the session details in it, it ended up creating a new session for every POST method request.
So in my app routine to create-session-if-not-exist, I just added a check to see if method is OPTIONS, and if so, just skip session creating part:
app.use(function(req, res, next) {
if (req.method !== "OPTIONS") {
if (req.session && req.session.id) {
// Session exists
next();
}else{
// Create session
next();
}
} else {
// If request method is OPTIONS, just skip this part and move to the next method.
next();
}
}
"preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Consider using axios
axios.get( url,
{ headers: {"Content-Type": "application/json"} } ).then( res => {
if(res.data.error) {
} else {
doAnything( res.data )
}
}).catch(function (error) {
doAnythingError(error)
});
I had this issue using fetch and axios worked perfectly.
I've encountered a very similar issue. I spent almost half a day to understand why everything works correctly in Firefox and fails in Chrome. In my case it was because of duplicated (or maybe mistyped) fields in my request header.
Use fetch instead of XHR,then the request will not be prelighted even it's cross-domained.
$.ajax({
url: '###',
contentType: 'text/plain; charset=utf-8',
async: false,
xhrFields: {
withCredentials: true,
crossDomain: true,
Authorization: "Bearer ...."
},
method: 'POST',
data: JSON.stringify( request ),
success: function (data) {
console.log(data);
}
});
the contentType: 'text/plain; charset=utf-8', or just contentType: 'text/plain', works for me!
regards!!