Client Credentials Flow works with curl but not in browser - javascript

I am developing a Spotify application and I want to get the token.
I am following Client Credentials Flow and using curl everything works fine:
$ curl -H "Authorization: Basic YjU4Y...llYTQ=" \
-d grant_type=client_credentials \
https://accounts.spotify.com/api/token
# Response:
# {
# "access_token":"BQD3u...W4iJA",
# "token_type":"Bearer",
# "expires_in":3600
# }
And here, there is the Javascript code of my HTML file where I try to get the same result:
var url = "https://accounts.spotify.com/api/token";
var authentication = "YjU4Y...llYTQ=";
var params = { grant_type: "client_credentials" };
var auth = "Basic " + authentication;
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
headers: {
'Authorization' : auth,
'Access-Control-Allow-Origin': '*'
},
data: params,
success: function(data) {
console.log('success', data);
}
});
However, I get the following error:
XMLHttpRequest cannot load https://accounts.spotify.com/api/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.
What am I doing wrong?
Is there really a way to use the Spotify API from a static HTML file using Javascript?

Nothing. Browsers disallow CORS unless the server specifically authorizes it. In your case, you don't control the server so you have only one choice - hack the browser. Easily done with plugins for Firefox and Chrome. Search for CORS Everywhere for Firefox. There one for chrome too called access control allow *, or something like that.
Trust me... I spent a week trying a different REST api. Tried js fetch, etc. You must hack the browser with the plugin.

Related

unable to correctly specify headers for CORS request

I created an AWS API Gateway endpoint that needs to be called from the browser. This is a simple jquery ajax post:
$.post(
'https://jhntqqm19l.execute-api.us-east-1.amazonaws.com/dev',
{}
)
(fiddle here: https://jsfiddle.net/7cfyr1mL/)
The browser says that the endpoint does not return appropriate CORS headers:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
however when I request this endpoint from python I see that the headers do exist:
# testing OPTIONS request
>>> res = requests.options('https://jhntqqm19l.execute-api.us-east-1.amazonaws.com/dev')
>>> print(res.headers)
200
>>> print(res.status_code)
{'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true', ...}
# testing POST request
>>> res = requests.post('https://jhntqqm19l.execute-api.us-east-1.amazonaws.com/dev', json={})
>>> print(res.headers)
{'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true', ...}
>>> print(res.status_code)
400
what is wrong with my headers? How do I change them so that the browser is happy?
Your server-side code throws a 500 error and doesn't set the Access-Control-Allow-Origin header if it gets a POST request which isn't JSON encoded.
jQuery POST uses standard form URL encoding by default, so you have to override that.
$.ajax(
'https://jhntqqm19l.execute-api.us-east-1.amazonaws.com/dev',
{ contentType: 'application/json', data: JSON.stringify({}), method: "post"}
);
You'll also need to change the server-side code to allow a preflight request as currently, you don't allow JSON formatted requests with CORS.
In server side code (python in your case) you will have to enable few things along with header
'Access-Control-Allow-Origin': '*'
You can refer to https://www.codecademy.com/articles/what-is-cors
and search how to apply cors based on your framework.
The browser makes an OPTIONS call before it actually makes any call to your application. Make sure it is enabled depending on your application.
For example allowedHttpHeaders, allowedHttpMethods, allowedOrigins.

Request header field Authorization is not allowed by Access-Control-Allow-Headers Google Maps Geocoding

I am trying to use google maps geocoding for my site. When I submit a request my code is as follows
GeocodeRequest.js
$http({
url: 'https://maps.googleapis.com/maps/api/geocode/json',
method: "GET",
headers: {
'accept': 'text / html, application/xhtml+xml,application/xml;q=0.9, image/webp,image/apng, */*;q=0.8',
'accept-language':'en-US,en;q=0.8,pl;q=0.6',
},
params: {
address: $scope.newVenue.Address + ", " + $scope.newVenue.City + ", " + $scope.newVenue.State,
key: 'MYKEY'
}
})
However in the console I am getting an error that states:
Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.
I have tried including
'Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS'
in my headers section but the error remains. Reading on this error I have found suggestions to install CORS but that is not an option in my case.
Any suggestions on how to fix this would be great. Thanks
you cannot resolve this on client side. Are you sure you are not sending Authorization header?
I had the same error. I am using Restangular and global settings always add Authorization header so I needed to override global settings by setting headers to empty object.
Hope it helps.

Uncaught (in promise) TypeError: Failed to fetch and Cors error

having a problem with getting data back from database. I am trying my best to explain the problem.
1.If I leave "mode":"no-cors" inside the code below, then I can get data back from server with Postman, but not with from my own server. Thinking it has to be my client side error
When I remove "mode":"no-cors" then I am getting 2 errors:
-Fetch API cannot load http://localhost:3000/. Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
-Uncaught (in promise) TypeError: Failed to fetch
Quick Browsing suggested to put in the "mode":"no-cors" which fixed this error, but it does not feel right thing to do.
So I thought maybe somebody has a suggestion how to approach this problem.
Really hope I was clear enough, but pretty sure I am not giving clear explanation here :S
function send(){
var myVar = {"id" : 1};
console.log("tuleb siia", document.getElementById('saada').value);
fetch("http://localhost:3000", {
method: "POST",
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "text/plain"
},//"mode" : "no-cors",
body: JSON.stringify(myVar)
//body: {"id" : document.getElementById('saada').value}
}).then(function(muutuja){
document.getElementById('väljund').innerHTML = JSON.stringify(muutuja);
});
}
Adding mode:'no-cors' to the request header guarantees that no response will be available in the response
Adding a "non standard" header, line 'access-control-allow-origin' will trigger a OPTIONS preflight request, which your server must handle correctly in order for the POST request to even be sent
You're also doing fetch wrong ... fetch returns a "promise" for a Response object which has promise creators for json, text, etc. depending on the content type...
In short, if your server side handles CORS correctly (which from your comment suggests it does) the following should work
function send(){
var myVar = {"id" : 1};
console.log("tuleb siia", document.getElementById('saada').value);
fetch("http://localhost:3000", {
method: "POST",
headers: {
"Content-Type": "text/plain"
},
body: JSON.stringify(myVar)
}).then(function(response) {
return response.json();
}).then(function(muutuja){
document.getElementById('väljund').innerHTML = JSON.stringify(muutuja);
});
}
however, since your code isn't really interested in JSON (it stringifies the object after all) - it's simpler to do
function send(){
var myVar = {"id" : 1};
console.log("tuleb siia", document.getElementById('saada').value);
fetch("http://localhost:3000", {
method: "POST",
headers: {
"Content-Type": "text/plain"
},
body: JSON.stringify(myVar)
}).then(function(response) {
return response.text();
}).then(function(muutuja){
document.getElementById('väljund').innerHTML = muutuja;
});
}
In my case, the problem was the protocol. I was trying to call a script url with http instead of https.
try this
await fetch(url, {
mode: 'no-cors'
})
See mozilla.org's write-up on how CORS works.
You'll need your server to send back the proper response headers, something like:
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
Bear in mind you can use "*" for Access-Control-Allow-Origin that will only work if you're trying to pass Authentication data. In that case, you need to explicitly list the origin domains you want to allow. To allow multiple domains, see this post
you can use solutions without adding "Access-Control-Allow-Origin": "*", if your server is already using Proxy gateway this issue will not happen because the front and backend will be route in the same IP and port in client side but for development, you need one of this three solution if you don't need extra code
1- simulate the real environment by using a proxy server and configure the front and backend in the same port
2- if you using Chrome you can use the extension called Allow-Control-Allow-Origin: * it will help you to avoid this problem
3- you can use the code but some browsers versions may not support that so try to use one of the previous solutions
the best solution is using a proxy like ngnix its easy to configure and it will simulate the real situation of the production deployment
Sometimes, please check your port number. If localhost port number is mismatch, you will get the same error as well.
I was getting this error and realized my server.js wasn't running.

Cross Origin Header Missing with jQuery Get Request but not with Python or in Browser [duplicate]

I'm calling this function from my asp.net form and getting following error on firebug console while calling ajax.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://anotherdomain/test.json. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
var url= 'http://anotherdomain/test.json';
$.ajax({
url: url,
crossOrigin: true,
type: 'GET',
xhrFields: { withCredentials: true },
accept: 'application/json'
}).done(function (data) {
alert(data);
}).fail(function (xhr, textStatus, error) {
var title, message;
switch (xhr.status) {
case 403:
title = xhr.responseJSON.errorSummary;
message = 'Please login to your server before running the test.';
break;
default:
title = 'Invalid URL or Cross-Origin Request Blocked';
message = 'You must explictly add this site (' + window.location.origin + ') to the list of allowed websites in your server.';
break;
}
});
I've done alternate way but still unable to find the solution.
Note: I've no server rights to make server side(API/URL) changes.
This happens generally when you try access another domain's resources.
This is a security feature for avoiding everyone freely accessing any resources of that domain (which can be accessed for example to have an exact same copy of your website on a pirate domain).
The header of the response, even if it's 200OK do not allow other origins (domains, port) to access the resources.
You can fix this problem if you are the owner of both domains:
Solution 1: via .htaccess
To change that, you can write this in the .htaccess of the requested domain file:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
If you only want to give access to one domain, the .htaccess should look like this:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin 'https://my-domain.example'
</IfModule>
Solution 2: set headers the correct way
If you set this into the response header of the requested file, you will allow everyone to access the resources:
Access-Control-Allow-Origin : *
OR
Access-Control-Allow-Origin : http://www.my-domain.example
Server side put this on top of .php:
header('Access-Control-Allow-Origin: *');
You can set specific domain restriction access:
header('Access-Control-Allow-Origin: https://www.example.com')
in your ajax request, adding:
dataType: "jsonp",
after line :
type: 'GET',
should solve this problem ..
hope this help you
If you are using Express js in backend you can install the package cors, and then use it in your server like this :
const cors = require("cors");
app.use(cors());
This fixed my issue
This worked for me:
Create php file that will download content of another domain page without using js:
<?
//file name: your_php_page.php
echo file_get_contents('http://anotherdomain/test.json');
?>
Then run it in ajax (jquery). Example:
$.ajax({
url: your_php_page.php,
//optional data might be usefull
//type: 'GET',
//dataType: "jsonp",
//dataType: 'xml',
context: document.body
}).done(function(data) {
alert("data");
});
You have to modify your server side code, as given below
public class CorsResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
}
}
You must have got the idea why you are getting this problem after going through above answers.
self.send_header('Access-Control-Allow-Origin', '*')
You just have to add the above line in your server side.
In a pinch, you can use this Chrome Extension to disable CORS on your local browser.
Allow CORS: Access-Control-Allow-Origin Chrome Extension

AngularJS Post request does not work correctly on firefox

I'm writing a website with AngularJS which communicates with an API on the server and provides some Info.
for Log in part I should send a http post request containing Email, Password and etc. It works fine on google Chrome and IE. I mean it sends the post request and gets a token. But in FireFox as I checked in Network, It sends an OPTION request and gets 200 but after that it does not send any post! hence my login would not disappear and I wont get any token.
what should I do for this situation?
App.config :
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8;';
$httpProvider.interceptors.push('httpRequestInterceptor');
Function in service which sends request :
this.loginEmail = function(f_email, f_pass, deviceModel, deviceOs) {
var data = $.param({
email: f_email,
password: f_pass,
device_model: deviceModel,
device_os: deviceOs
});
return $http({
method: "POST",
url: app.baseUrl + 'login_email/' + app.storeID + '/' + app.device_id,
data: data
}).success(function(response){
return response.status;
});
/*return $http.post(app.baseUrl + 'login_email/' + app.storeID + '/' + app.device_id, data).success(function(response){
return response.status;
}).error(function(response){
return response.status;
});*/
};
Server Credentials are true
CORS seems fine because I can do get request
EDIT:
Here's another thing that may be related to this problem:
in Chrome when I get logged in for get requests it sends the Token header
but for Post it doesn't
httpRequestInterceptor :
app.factory('httpRequestInterceptor', function ($cookieStore) {
return {
request: function (config) {
config.headers['Authorization'] = $cookieStore.get('Auth-Key');;
config.headers['Accept'] = 'application/json;odata=verbose';
return config;
}
};
});
The problem was caused by apache configurations.
before:
Access-Control-Allow-Headers: "authorization"
after:
Access-Control-Allow-Headers: "authorization, Content-type"
UPDATE :
On CORS requests if API requires some special headers like Auhtorization Token you must return all OPTIONS requests 200(ok!) if not the solution above would not work anyway.
Here's the code:
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header( "HTTP/1.1 200 OK" );
exit();
}
UPDATE 2 :
This OPTIONS problem occurs in REST framework for Django! For OPTIONS it evaluates the request by pursing whole api if there was a problem in it, you'll get error even though you have required permissions for sending request!
Example:
Suppose that there's a url like api/profile which needs an Authorization header for responsing profile details. You want to send the Cross Domain request for getting it. You set the right headers and click! You'll get unauthorized error! Why? Because the pre flighted request(OPTIONS) does not include any special header and browser sends it to server, server with REST framework evaluates the OPTIONS request by checking the whole request(get request with authorization header) but OPTIONS doesn't have any authorization header so this request is unauthorized!
DEVELOPMENTAL SOLUTION :
This problem can be solved either by Client-Side or Back-End. Front-End developer can install following plugin on chrome:
Allow-Control-Allow-Origin: *
Back-End developer can install a package which enables CORS on Django Framework.

Categories