I am trying to use the Cloudinary REST API, but the client libraries provided are not useful for my purpose.
So the settings I use are:
api_key = '111111111111111';
api_secret = 'fdgdsfgsdfgsdfgsdfgsdfg';
my_authorization = 'Basic ' + window.btoa(this.api_key + ':' + this.api_secret);
url_base = 'http://api.cloudinary.com/api/v1_1';
cloud_name = '/http-mysite-com';
connect_method = 'GET';
tag_list = '/tags/image';
I make the call with something similar to this:
request(tag_list) {
connection.request({
method: connect_method,
url: url_base + cloud_name + service_url,
headers: {
'Authorization': authorization,
'Content-Type': 'application/json'
}
}).then(function(response) {
// triumph
}, function(er) {
// all is lost
});
};
The response is this:
XMLHttpRequest cannot load
http://api.cloudinary.com/api/v1_1/http-mysite-com/tags/image. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://myhost:8000' is therefore not allowed
access. The response had HTTP status code 404.
What am I doing wrong?
Thanks
PS I also tried using 'https' instead of 'http', as the documentation recommends. In that case I get back:
XMLHttpRequest cannot load
https://api.cloudinary.com/v1_1/http-mysite-com/tags/image. The
request was redirected to
'http://api.cloudinary.com/api/v1_1/http-mysite-com/tags/image',
which is disallowed for cross-origin requests that require preflight.
Admin API calls use your api_secret which should not be revealed in your client-side code. That's why Cloudinary doesn't support CORS headers for the Admin API.
Therefore, Admin API calls should be performed on the server-side only.
Related
I am attempting to follow this EBAY User Consent API article https://developer.ebay.com/api-docs/static/oauth-consent-request.html
but I am getting a CORS error "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've read numerous Cors posts here this one being a good one: XMLHttpRequest cannot load XXX No 'Access-Control-Allow-Origin' header but none of these solutions seem to work.
a pointer in the right direction would be great.
$(document).on('click','.ebay_access', async function(event) {
let scopes = encodeURIComponent("https://api.ebay.com/oauth/api_scope https://api.ebay.com/oauth/api_scope/sell.marketing.readonly https://api.ebay.com/oauth/api_scope/sell.marketing https://api.ebay.com/oauth/api_scope/sell.inventory.readonly https://api.ebay.com/oauth/api_scope/sell.inventory https://api.ebay.com/oauth/api_scope/sell.account.readonly https://api.ebay.com/oauth/api_scope/sell.account https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly https://api.ebay.com/oauth/api_scope/sell.fulfillment https://api.ebay.com/oauth/api_scope/sell.analytics.readonly https://api.ebay.com/oauth/api_scope/sell.finances https://api.ebay.com/oauth/api_scope/sell.payment.dispute https://api.ebay.com/oauth/api_scope/commerce.identity.readonly https://api.ebay.com/oauth/api_scope/commerce.notification.subscription https://api.ebay.com/oauth/api_scope/commerce.notification.subscription.readonly");
let clientId = "{{env('EBAY_APIKEY')}}";
let clientSecret = "{{env('EBAY_API_CERT_NAME')}}";
let oAuthCredentials64 = btoa(clientId + ":" + clientSecret);
let endpoint = 'https://api.ebay.com/identity/v1/oauth2/token';
try{
let response = await fetch(endpoint,
{
method: "POST",
headers:
{
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": `Basic ${oAuthCredentials64}`
},
body:
"grant_type=client_credentials&scope=" + scopes
}
);
let responseJson = await response.json();
console.log("CLIENT ACCESS TOKEN", responseJson);
} catch(err){
console.log("error: ", err);
};
}); //end function
The request you are making seems to be an authentication request, or "consent request", as eBay call it. This must be made to the authorization endpoint (probably https://api.ebay.com/identity/v1/oauth2/authorize). But you make it to the token endpoint (https://api.ebay.com/identity/v1/oauth2/token), as if it were a token request. But the token request is only the second step ("Exchanging the authorization code for a User access token").
Moreover, neither the authentication request nor the token request are CORS requests:
The authentication request must happen in a visible browsing context, as explained here. The user can only consent if they see what is going on.
The token request is not made by the browser, because this would expose the secret (as pointed out in Jags's answer). It must be made by your server.
In other words: No CORS should be involved at all. The eBay API article explains this correctly.
There are multiple issues here.
In general, if the URL - domain on your browser is not same as the ajax call browser is making then you get this error.
Seems that you have copied the code which was meant for server side execution. You should NEVER expose your credentials to client side. Anyone can use your steal your credentials.
The github link you provided as reference is for server side nodejs application which is running as an app and not under browser.
I'm writing a full stack app. I have a python backend using flask that sends a file and a Vue client that receives. Its been working fine up until the point when I try to send the filename over using a Content-Disposition header.
On the backend I've tried:
return send_file(base_path + filename, as_attachment=True, download_name=filename)
And to set the headers manually,
response = make_response(send_file(base_path + filename))
response.headers['Content-Disposition'] = f"attachment; filename=\"{filename}\""
return response
I've also tried to put in headers that would not be blocked by CORS just to see if the request would receive the header but to no avail,
response = make_response(send_file(base_path + filename))
response.headers['Content-Type'] = "sample/info"
return response
I'm printing the header to the console by doing
fetch('http://localhost:4999/rdownload/' + this.$route.params.id, {
method: 'GET'
}).then(res =\> {
if (res.status == '500') { }
console.log(res.headers)
//const header = res.headers.get('Content-Disposition');
//console.log(header)
res.blob().then((blob) => {
/* ... */
})
})
Any help would be appreciated! Thanks :)
Research
In the interest of logging the solution I found and helping out anyone in the future who may be interested in knowing the answer here's what I discovered:
There is a restriction to access response headers when you are using Fetch API over CORS.
https://stackoverflow.com/a/44816592/20342081
So, no matter what using the JS fetch-api you will be unable to access all headers (outside of Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma) unless you expose them by specifying them in a request header. That would look something like this:
fetch('https://myrequest/requestend/', {
headers: {
'Access-Control-Expose-Headers': 'Content-Disposition'
}
})
When a cross-origin source accesses your API you will have to expose the header from the back end as well. https://stackoverflow.com/a/66291644/20342081
I was also confused about how the differences between Access-Control-Expose-Headers and Access-Control-Allow-Headers. In my case the solution was use "expose headers" on both the frontend and the backend (and allow wouldn't work). However, Allow has its own applications which I have yet to understand fully. For those endeavoring check out: https://stackoverflow.com/a/28108431/20342081
Solution
I implemented these things in my code by doing:
class RequestResult(Resource):
def get(self, index):
base_path = f"Requests/{index}/"
filename = os.listdir(base_path)[0]
response = make_response(send_file(base_path + filename, as_attachment=True, download_name=filename))
response.headers['Access-Control-Expose-Headers'] = "Content-Disposition"
return response
And on the front end exposing the header as well on the fetch request:
fetch('http://localhost:4999/rdownload/' + this.$route.params.id, {
method: 'GET',
mode: 'cors',
headers: {
'Access-Control-Expose-Headers': 'Content-Disposition'
}
})
I hope this is helpful for the next 5 people who open this in the next 10 years!
I am trying to access linkedin profile using axios get request, which doesn't work on localhost and I get the following error
XMLHttpRequest cannot load
https://api.linkedin.com/v1/people/~:(id,email-address)?format=json.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8030' is therefore not allowed
access. The response had HTTP status code 401.
I am able to get access-token using react-linkedin-login package, after getting the access token I am trying the following code
var linkedInUrl = `https://api.linkedin.com/v1/people/~:(id,email-address)?format=json`;
var headers = {
'Authorization': `Bearer ${accessToken}`,
'Access-Control-Allow-Methods':'GET,PUT,PATCH,POST,DELETE',
'Access-Control-Allow-Origin':'*',
'Access-Control-Request-Headers':'Origin, X-Requested-With, Content-Type, Accept',
'Content-Type':'application/x-www-form-urlencoded'
};
return (dispatch) => {
axios.get(linkedInUrl, {headers}).then(({data}) => {
console.log(data);
}, (error) => {
console.log(error);
});
}
The problems lies in linkedin server how it takes request I guess, it doesn't allow localhost to make call I think. How to overcome this to actually develop the service before I deploy and run on server.
Thanks for helping..
This is because of a browser restriction called the "Same-origin Policy", which prevents fetching data from, or posting data to, URLs that are part of other domains. You can get around it if the other domain supports Cross-origin Resource Sharing (CORS), but it looks like LinkedIn doesn't, so you may have trouble.
One way around this is to have a web service which can proxy your request to LinkedIn - there's no domain restrictions there.
https://en.wikipedia.org/wiki/Same-origin_policy
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
try jsonp for CORS request - reference - axios cookbook
var jsonp = require('jsonp');
jsonp(linkedInUrl, null, function (err, data) {
if (err) {
console.error(err.message);
} else {
console.log(data);
}
});
EDIT
Use jQuery to perform JSONP request and to set headers
$.ajax({url: linkedInUrl,
type: 'GET',
contentType: "application/json",
headers: header, /* pass your header object */
dataType: 'jsonp',
success: function(data) {
console.log(data);
},
error: function(err) {
console.log('Error', err);
},
});
https://cors-anywhere.herokuapp.com/ - Add this before the url and it will work
I try to get issues from redmine via them Rest Api. When I call it from Postman I get response, but when I do it from my angular App I get such error
OPTIONS https://redmine.ourDomain.net/issues.json 404 (Not Found)
XMLHttpRequest cannot load https://redmine.ourDomain.net/issues.json. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 404.
Its how I do it in Angular
login(user: User): Observable<boolean> {
var headers: Headers = new Headers();
headers.append("Authorization", "Basic " + btoa(user.login + ":" + user.password));
let options = new RequestOptions({ headers: headers });
return this.http.get("https://redmine.ourDomain.net/issues.json", options)
.map((response: Response) => {
debugger;
if (response.status == 200) {
// set token property
// store username and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify({ user }));
// return true to indicate successful login
return true;
} else {
// return false to indicate failed login
return false;
}
});
}
And there how request looks in my browser
You'll need to enable CORS access on the backend: http://www.redmine.org/plugins/redmine_cors
Here's a nice extension that will let you test frontend code outside of normal CORS restrictions. It's strictly for testing and won't help a production app, but nice to have: https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi
CORS must be set up in the backend. Please note that is NOT a good practice to allow all origins Access-Control-Allow-Origin: '*' and that you will need to specify the other headers as well:
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: authorization.
I would like to know your opinion on the issue in this simple code in ajax, which has the problem Access-Control-Allow-Origin, already tried several ways defenir the ember "Access-Control-Allow-Origin": "* " but without success, so I wonder if someone with the same problem found a solution.
I use the url address localhost: 4200 and already tried with a subdomain of firebase in both cases the error was always the same.
The ajax request:
import Ember from 'ember';
import { isAjaxError, isNotFoundError, isForbiddenError } from 'ember-ajax/errors';
export default Ember.Controller.extend({
ajax: Ember.inject.service(),
actions: {
code() {
var cliente = '***';
var redirectUri = 'http://localhost:4200/teste';
var client_secret = '***';
var code = '***';
var grant_type = 'authorization_code';
var data =
"client_id=" + cliente +
"&redirect_uri=" + encodeURIComponent(redirectUri) +
"&client_secret=" + client_secret +
"&code=" + code +
"&grant_type=" + grant_type;
this.send('post', data)
},
post(data) {
this.get('ajax').post("https://login.live.com/oauth20_token.srf", {
method: 'POST',
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/x-www-form-urlencoded",
},
data: data,
dataType: 'JSON',
});
},
}});
My content Security Policy:
contentSecurityPolicy: {
'connect-src': "'self' http://localhost:4200 https://*.googleapis.com https://login.live.com/oauth20_token.srf",
'child-src': "'self' http://localhost:4200",
'script-src': "'self' 'unsafe-eval' https://login.live.com",
'img-src': "'self' https://*.bp.blogspot.com https://cdn2.iconfinder.com http://materializecss.com https://upload.wikimedia.org https://www.gstatic.com",
'style-src': "'self' 'unsafe-inline' ",
},
The error is:
XMLHttpRequest cannot load https://login.live.com/oauth20_token.srf. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
This doesn't actually seem like an Ember related question. The problem you are having is exclusively backend related. For ajax requests to work backend should serve the proper 'Access-Control-Allow-Origin' header in response. Otherwise your browser would not accept such responses and throw an error that you are seeing. It's not Ember related in any way it's just how browsers work.
Now to fix this issue you would have to add the proper client server name to your backend 'Access-Control-Allow-Origin' headers. I.e. if you are going to serve your Ember app from https://example.com that is what you need to add to 'Access-Control-Allow-Origin' header.
So let's assume you just want the ways to bypass this messages.
There are plenty of browser extensions that would disable CORS check in your browser for development. This way would work just fine if you are using localhost but plan to move to real server in the future and have a way to actually set 'Access-Control-Allow-Origin' header on backend.
Let's assume you don't have any way to change the backend header now but desperately want to test how the client app would work on your remote https://example.com. You would have to setup a remote server to proxy all your requests to the target backend modifying the headers that are sent in response so your browser would accept them. This way you don't have to use any chrome extensions to disable CORS.
One of the simplest ways to setup such server would be to use the following package - https://www.npmjs.com/package/express-http-proxy . The configuration for your case would be pretty straightforward.
sample express app:
var proxy = require('express-http-proxy');
var app = require('express')();
app.use('/', proxy('www.example.com', {
intercept: function (rsp, data, req, res, callback) {
res.append('Access-Control-Allow-Origin', '*');
callback(null, data);
}}));
app.listen(3000, function () {
console.log('listening on port 3000');
});