I am testing the jquery ajax calls to the API server from a different domain. Unfortunately I am getting an OPTIONS error. Here is my request code:
$.ajax({
url: "https://localhost:44356/api/Default/",
headers: {
"Authorization": "Bearer " + user.access_token
},
success: function (res) {
logAjaxResult(res);
},
error: function() {
logAjaxResult('Error');
}
}))
Which gives
XMLHttpRequest cannot load https://localhost:44356/api/Default/. Response for preflight has invalid HTTP status code 405.
Normally this is an easy fix - I install Microsoft.AspNet.WebApi.Cors, set up a provider and allow OPTIONS through always. I can see how I would normally do this on the Identity Server box too as there is a CorsProvider you can register up. My issue however is on the API box I am using IdentityServerBearerTokenAuthenticationOptions and I see no CORs options. When I try to set up the WebAPI.cors provider though I get an error saying there are multiple origins set on the server to allow. This indicates to me (correct me if I'm wrong) that the WebApi box has somehow got the CORs settings from my identity server box that is registered as it's authority. Is this right?
How do I configure to allow pre-flight requests with app.UseIdentityServerBearerTokenAuthentication(options)?
Many thanks
This issue was resolved when I found the documentation uses
Microsoft.Owin.Cors
I was using the package
Microsoft.AspNet.WebApi.Cors
Related
I am using google business API and trying to get location list.
I am going trough their documentation and using project from the link below as basis
https://developers.google.com/my-business/content/implement-oauth
Using that project I am able to successfully retrieve accounts list.
The problem occures when I try to retrieve locations list using accountID. Here is a link for their documentation
https://developers.google.com/my-business/content/manage-locations
Acording to documentation, to get location list for specific account, I should use following request
GET
https://mybusinessbusinessinformation.googleapis.com/v1/{accountId}/locations
Authorization: Bearer <access_token>
This is the code snippet, that I added to their sample project
function retrieveGoogleMyBusinessLocations(accessToken) {
$.ajax({
type: 'GET',
url: 'https://mybusinessbusinessinformation.googleapis.com/v1/{accID}/locations',
headers: {
'Authorization' : 'Bearer ' + accessToken
},
success: function(returnedData) {
var e = document.createElement("pre")
e.innerHTML = JSON.stringify(returnedData, undefined, 2);
document.body.appendChild(e);
}
});
}
When I do this request, it gives "CORS error".
The error in the console is following
Access to XMLHttpRequest at 'https://mybusinessbusinessinformation.googleapis.com/v1/xxx/locations' from origin 'http://localhost:8001' 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.
GET https://mybusinessbusinessinformation.googleapis.com/v1/xxx/locations net::ERR_FAILED
From the error message it seems that server does no accept requests from localhost:8001, but if I do request to different endpoint it will return result.
For example if I change utl from
https://mybusinessbusinessinformation.googleapis.com/v1/{accID}/locations
to
https://mybusinessbusinessinformation.googleapis.com/v1/accounts/{accID}/locations?readMask=categories
With the second url it will return successfull result.
I am confused why it is allowing requests to one endpoint and blocks requests to other endpoint.
Can anyone help with this problem?
Have you tried making direct API requests via the Google Developers OAuth 2.0 Playground?
I tried to reproduce your error but got the expected 404 Not Found response for the unsupported endpoint pattern.
curl -v -X POST -H "Authorization: Basic <base64 encoded client id:client secret value>" -k -d "grant_type=password&username=<username>&password=<password>" -H "Content-Type:application/x-www-form-urlencoded" https://localhost:9443/oauth2/token
(from https://docs.wso2.com/display/IS520/Resource+Owner+Password+Credentials+Grant
)
This 'curl' command works perfectly. But when try to call it through ajax:
$.ajax({
type: 'POST',
data: 'grant_type=password&username=admin&password=admin',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic Z0hLUlA3eThYTmJydl9JR1pJemxDQ1VJQlo0YTozT2VLaUlmUVViMk1yZzZ2YU5uQVFsWFpDU29h'
},
url: 'https://localhost:9443/oauth2/token',
success: function(data) {
console.log(data);
}
})
};
I got this error: "XMLHttpRequest cannot load https://localhost:9443/oauth2/token. 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."
How can I configure WSO2 IS to deal with it? Or is there an alternetive for this?
There is a similar issue with WSO2 API Manager (WSO2 API Manager CORS). But there is no such directory '/repository/deployment/server/synapse-configs/' in WSO2 IS.
This is the expected behaviour when cross origin resource sharing (CORS) is not enabled on Identity Server. In fact you can enable CORS for Identity Server. Check [1] on how to do it.
[1] http://hasanthipurnima.blogspot.com/2016/05/applying-cors-filter-to-wso2-identity.html
I don't think the Token API of IS returns CORS headers. To get this working, you can front Token API of IS by API Manager. By default, APIM returns CORS headers in all REST APIs you create in it.
In fact, API Manager ships an API (i.e. https://localhost:8243/token) which fronts the token API of IS (i.e. https://localhost:9443/oauth2/token) (note: APIM has certain IS features installed in it). But it does not return CORS headers too. To make it return CORS headers, you should follow that SO link you have mentioned.
Another simple option is, if you only need CORS headers, you can simply front Token API of IS by another custom services which returns CORS headers in the response.
We are trying to implement Github oAuth in our app using Passport.js. If the user hits the endpoint by clicking an anchor tag/href, it works fine, but if we use a click handler to initiate an ajax request instead, we receive a CORS error from the Github server. Why?
Server side code:
app.get('/auth/github',
passport.authenticate('github', { scope: [ 'user:email' ] }));
app.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/login' }),
function(req, res) {
console.log('Github authentication successful!');
res.redirect('/');
});
Client side code (we are using React):
--> Works:
<a href='/auth/github'>Contact</a>;
--> Does Not Work - CORS error:
handleContactAuth(event) {
$.ajax({
url: '/auth/github',
method: 'GET',
success: data => console.log( 'Contact Auth response: ', data),
error: err => console.log( 'Error connecting to GitHub.', err)
});
}
NOTE: This is a click handler on the React component and is functioning fine, as the ajax request is being triggered. I'm aware we're not handling the response currently, apart from just a console.log.
--> CORS Error we see on the Client side when using AJAX method instead of href:
XMLHttpRequest cannot load https://github.com/login/oauth/authorize? response_type=code&redirect_uri=ht…auth%2Fgithub%2Fcallback&scope=user%3Aemail&client_id=our_client_code. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
Any ideas? Would appreciate any insights - many thanks.
CORS error is not an error returned by the server, but one triggered by the browser if the response doesn't contain HTTP headers signaling that cross-origin requests are allowed. The endpoint you are hitting obviously isn't designed to be accessed like this.
I had the same problem and I found that at least in Google Chrome XMLHttpRequest object is restricted to same origin policy. So you may need to stick to using an anchor tag.
Regular web pages can use the XMLHttpRequest object to send and receive data from remote servers, but they're limited by the same origin policy. Extensions aren't so limited. An extension can talk to remote servers outside of its origin, as long as it first requests cross-origin permissions.
Link: https://developer.chrome.com/extensions/xhr
I tried to access a Rest service which was hosted in different domain from mine through an ajax call and I got "CORS" error in the firebug.
After researching about this problem, I figured out that the service needs to be changed by adding Access-Control-Allow-Origin to * in the response header. I did that in the service as well.
public Response search(String expression) {
return Response.ok() //200
.entity(ConnectionUtils.query(expression))
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.header("Access-Control-Allow-Headers", "Content-Type,Accept")
.allow("OPTIONS").build();
}
Above method is the implementation class of below service interface:
#POST
#Path("/search")
public Response search(String expression);
I tried to post a request to this url through chrome advanced rest client, I am getting the response as well. Also the response header shows that the Access-Control-Allow-Origin has been set properly as well. Please refer to below screenshot of chrome client:
If you see above, the response headers has been changed.
But my below ajax call always return CORS error:
"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://192.168.1.100:8080/cqs-1.0-SNAPSHOT/services/services/cqs/search. This can be fixed by moving the resource to the same domain or enabling CORS."
$.ajax({
type: 'POST',
url: "http://192.168.1.100:8080/cqs-1.0-SNAPSHOT/services/services/cqs/search",
crossDomain: true,
dataType: 'json',
data: {"offer.offer.offerId.USSellerId": {$gt: 0}},
headers: {
"Accept": "application/json",
contentType: "application/json"
},
success: function (data) {
console.log(data);
},
error: function (data) {
console.log(data.statusText);
console.log(data.name);
}
});
Don't use CORS. It's fraught with peril. Rather, set up a simple reverse proxy on the server using Apache (or similar). Once you set it up, all requests from your app can go back to your domain/port thus not triggering any OPTION methods from the browser. Meanwhile your reverse proxy can redirect requests based on the path in the url, which is completely up to you on how you want to configure.
In my case, I just had a simple case of needing to access 2 different ports on the same server. Port 8080 (tomcat) was serving my GWT UI and REST requests from my GWT pages (using RestyGWT) were needing to hit port 9000 (Play framework port). Due to the different ports, CORS was required to deal with the OPTION 'preflight' checks that the browser was doing.
To solve this I just setup my URLs as having either /ui path or a /api path.
Since the domain/port was the same, and my proxy could easily redirect transparently to the correct port (api -> 9000 and ui -> 8080) there was no longer any need for CORS.
CORS has a lot of issues in my experience including cookies. It's really better to avoid it using a reverse proxy.
If you need more details, I can post more - let me know.
JR
On domain A (localhost:8080) I run this code to access an unauthenticating REST serivce on domain B (localhost):
req = new XMLHttpRequest();
req.open('GET', 'http://localhost/rest/service');
req.send();
This works fine and I do get my response across domains as I have Apache on domain B set the response header:
Header set Access-Control-Allow-Origin "http://localhost:8080"
However if I now turn on authentication for the REST service and try to run the same request:
req.open('GET', 'http://admin:admin#localhost/rest/service');
It now produces this error in Firebug:
Access to restricted URI denied" code: "1012
I'm confused that I am able to sucessfully make cross domain ajax calls to the authenticated service bypassing the same origin policy, yet when authentication is required on the service Firefox decides not to allow the ajax call? How can I fix this without using jsonp etc, as the production server won't be able to provide PHP or Servlet hosting.
It's easy with JQuery 1.5+, which I recommend you use for your JavaScript solution:
$.ajax({
url: 'http://admin:admin#localhost/rest/service',
crossDomain:true, // Here is the JSONP callback logic
success: function(data){
console.log(data); // data is what comes back from your remote file
}
});