I have a web app that allows people to generate a list of songs by artists that are related to a particular artist. I want to be able to connect to the user's Spotify account and create a playlist for them from that list of songs, but I need to get an access token. I have a developer account and client ID and am trying to work through the Authorization Flow, but it's not working for me. Instead, I get this error: XMLHttpRequest cannot load https://accounts.spotify.com/authorize/?client_id=d137fe25b31c4f3ba9e29d85f…:3000/callback&scope=user-read-private%20user-read-email&state=34fFs29kd09. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
This is a portion of my scripts.js file (i'm using the spotify-web-api-js node module):
$('#spotify').on('click', function() {
$.support.cors = true;
$.getJSON("https://accounts.spotify.com/authorize/?client_id=d137fe25b31c4f3ba9e29d85f4e47c66&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcallback&scope=user-read-private%20user-read-email&state=34fFs29kd09", function(json2){
$.getJSON("https://accounts.spotify.com/api/token/?grant_type=authorization_code&code=" + json2.code + "&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcallback&client_id=d137fe25b31c4f3ba9e29d85f4e47c66&client_secret={...}", function(json3) {
s.setAccessToken(json3.access_token);
});
});
});
});
According to my research, it's a CORS-related issue. I'm making edits to my ExpressJS server to remedy this cross-origin problem and installed the cors node module, but I'm still getting the same error.
index.js server:
var express = require('express');
var cors = require('cors');
var app = express();
var port = 3000;
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.use(express.static(__dirname + '/public')); // looks in public directory, not root directory (protects files)
app.get('/', function(req, res) {
res.send(__dirname + '\\index.html')
});
app.listen(port, function() {
console.log('CORS-enabled web server listening on port ' + port);
});
When I go to the URL in question directly through my browser, it gives me the expected "Do you authorize this app to use your Spotify information" form.
Should I require 'cors' in 'scripts.js' for it to work? Does anyone have any other suggestions?
I believe the issue here is that you're attempting to retrieve JSON data from the endpoint where you should direct your users. So instead of making a request to it, you should supply a button on your page that links to your https://accounts.spotify.com/authorize/{...} URL. The user will proceed to give your application the permissions you've requested as specified in the scope parameter, and will be directed back to the URL you've specified in the redirect_uri parameter. This is where you get the authorization code, which you can use in the https://accounts.spotify.com/api/token/{...} endpoint. Read more about the Authorization Code flow in the Authorization Guide.
Spotify Web API support three different oAuth flows, and you might be interested in Implicit Grant. Examples of all of these flows written in Javascript using Node is available at https://github.com/spotify/web-api-auth-examples.
Related
I'm developing a web application that uses the Twitter API REST. I have a page with Twitter accounts and a button for adding a new account. When the button is pressed, the function in the Angular controller is executed:
// Calls token to add a new Twitter user
$scope.callToken = function () {
$http.get('/token')
.then(function (response) {
console.log(response);
});
};
This is the code in the backend to serve de request. It simply redirects to Twitter to add a new user.
// routes.js
var token = express.Router();
token.route('/token')
.get(cuentasCtrl.getToken);
// Account file
exports.getToken = function(req, res) {
twitter.getRequestToken(function(err, requestToken, requestSecret) {
if (err)
res.status(500).send(err);
else {
_requestSecret = requestSecret;
res.setHeader('Access-Control-Allow-Origin', '*');
res.redirect("https://api.twitter.com/oauth/authenticate?oauth_token=" + requestToken);
}
});
};
But I get the next error:
Origin 'http://localhost:3000' is therefore not allowed access Twitter API
My server is running on localhost:3000 and If I put localhost:3000/token in my browser there is no problem. I have read the solutions for using CORS and tested other browsers but it hasn't worked for me. What have i done wrong?
The redirect you are sending in your express response is caught by the http client you use in the frontend and the redirect happens there. You are in a classical CORS situation and of course this is not how you can interact with the Twitter rest APIs.
You have to make http calls to Twitter on the node side (server to server) or use a client side client library for Twitter (https://dev.twitter.com/web/javascript)
I am trying to integrate facebook login for my app in nodejs, angularjs using passport-facebook module.
I can intergrate facebook authentication without angularjs, but when i use angular http.get('/auth/facebook')
i am getting below error
XMLHttpRequest cannot load https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%…%2Flocalhost%3A1439%2Fauth%2Ffacebook%2Fcallback&client_id=xxxxxxxx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:1439' is therefore not allowed access.
app.js:153 err
Below is my angular code
var headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Content-Type': 'text/html'
};
$scope.fblogin=function(){
// $window.location.href='/auth/facebook';
$http({
url:'/auth/facebook',
method:'GET',
headers: headers
}).success(function(data){
console.log(data);
}).error(function(){
console.log('err');
});
};
pp.config(['$routeProvider','$httpProvider',
function($routeProvider,$httpProvider) {
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.headers.common = 'Content-Type: application/json';
delete $httpProvider.defaults.headers.common['X-Requested-With'];
NodeJs
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
**Note:**I have tried changing multiple header changes for $http.get()
Solution:
The link https://www.facebook.com/dialog/oauth?... is not designed for calling it as ajax because it must REDIRECT user to facebook login page (so when you call it by ajax then redirect is impossible).
Instead of make ajax request just prepare in html proper element:
<a href="https://www.facebook.com/dialog/oauth?..." > ... </>
This works :)
This is what I have done to avoid Angular to call facebook auth dialogue API as AJAX request.
Use 'window.location="http://localhost:3000/auth/facebook"'; in your Angular Controller Function from where you send the request to your Express Server which contains passport.authenticate stuff.
Example:
$scope.authFacebook = function() { window.location="http://localhost:3000/facebook" }
You are attempting to make an ajax call to a URL and the browser is rejecting that ajax request because of cross origin security.
There are several possible reasons for this:
The domain of that URL doesn't allow cross origin requests.
You aren't making the request in a proper way for the cross origin request to succeed.
Your request is not formed properly (either targeted at the right URL or sent with the right options).
FYI, your node.js code where you set the allow-origin headers has absolutely nothing to do with the browser code attempting to send an ajax call to Facebook. That code would allow other people's web sites to make cross origin requests to your node.js server.
One thing that is a bit confusing about what you posted is that the URL of the $http() call you show is not the same URL as you are getting in the error message so I'm wondering if you're looking at the wrong code for the error.
This solution works for me, adding to cors to express app
var cors = require('cors')
var app = express()
app.use(cors())
var express = require('express');
var app = express();
var path = require('path');
var api = require('./api');
app.get('/', function(req, res){
res.sendFile(path.join(__dirname + '/index.html'));
})
app.listen(8080)
console.log('Server Running');
I know that we are requiring the express module. We are using the express function, we are requiring the module path and storing the reference in variable path and doing the same with api but beyond that I am a little lost. If I wanted to connect to twitter API how would I go about doing this? Can someone please explain the logic behind it so i can go learn this better and apply it by myself with different API's? I sincerely and greatly appreciate all of your help!
Express is a framework for organising your web application server. You open up certain API's routes to listen on the path and respond to the requests when necessary.
You can open API's only for internal use, i.e. calls from the browser running your app. Or you can expose your API to outer world (for example twitter API is doing that).
To connect to twitter API you need to make an outgoing request from your webserver. There are many ways to go about that, starting from native nodeJS package http https://nodejs.org/api/http.html to much more popular alternative request https://github.com/request/request
One thing to note here is that NodeJS web server are in general less restrictive than other language servers, especially when it comes to organising your app and code architecture. Hence more issues for beginners. Feel free to ask more questions.
Main purpose of app in
var app = express()
is to listen to routes (it is as well used to render pages, adding middleware etc.) and only that.
So assume u have a button on your UI which allows you to connect to twitter API. So on the click you make a GET request to your own server, to /api/twitter/connect .
On your server you listen on this path as follows:
var request = require('request'); //assuming you installed this module
app.get('/api/twitter/connect', function(req, res){
request(TWITTER_API_URL + API_KEYS, function(err, body){
res.json(body); //res is the response object, and it passes info back to client side
});
});
You can use "request" package to send requests. But in case of Cross-Origin-Request you must use "HTTPS" instead of "HTTP". You can configure Your request according to your request type like this..
//Load the request module
var request = require('request');
//Lets configure and request
request({
url: 'https://example.com/abc/demo', //URL to hit
qs: {from: 'example', time: +new Date()}, //Query string data
method: 'GET', // specify the request type
headers: { // speciyfy the headers
'Content-Type': 'MyContentType',
'Custom-Header': 'Custom Value'
},
body: 'Hello Hello! String body!' //Set the body as a string
}, function(error, response, body){
if(error) {
console.log(error);
} else {
console.log(response.statusCode, body);
}
});
Besides this there are others way to do the same. And for twitter you can also checkout the module called "twitter"
Answers to this question explain how to route sub domains in Node.js with Express.
I want to know how to do it without Express.
Here's my server module, which returns a server object:
module.exports.serve = function(port) {
var server = https.createServer(options, function(req, res) {
// Parse & process URL
var reqInfo = url.parse(req.url, true, true),
path = reqInfo.pathname;
debug.log("Client [" + req.connection.remoteAddress +
"]requesting resource: " + path);
// Quickly handle preloaded requests
if (preloaded[path])
preloadReqHandler(req, res, preloaded[path], path);
// Handle general requests
else generalReqHandler(req, res, reqInfo);
}).listen(port);
return server;
};
No need to go into detail with the modules that handle the requests, I'm just interested in how to detect www.example.com and route it to example.com or vice-versa, via my server.
Just to add as much detail as possible, my goal here is to route all traffic from http://www.example.com and http://example.com and https://www.example.com and send it all to https://example.com. To do that, I think I just need to learn how to route the www sub domain, and then listen on both the http and https ports for that routing.
Since HTTP 1.1, user agents send the Host request header which specifies the domain. So you can get the domain (including the port if specified) from req.headers['host'] and apply your custom domain routing logic.
If you're talking with a HTTP 1.0 or older user agent, then just reply with "505 HTTP Version Not Supported" or serve some default content.
I am trying to connect my cordova/phonegap application with my node.js server. Problem is, I get this error "XMLHttpRequest cannot load http://127.0.0.1:1234/api/users. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:5000' is therefore not allowed access. The response had HTTP status code 500. " . I tried adding this middleware to my node.js server, entering my phonegap domain, then, just for testing purpouses of course, I figured I will allow ALL domains for CORS, still no luck. This is what I used on my node.js server:
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', '*');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
And I am doing a pretty simple AJAX request from my phonegap application, which I think is pretty much correct. I am getting this error on my phonegap app and on the node.js server console I get an error from one of the controllers, saying can't see property X of undefined, which undefined is my req.body. Here is the request:
var serverURL = 'http://127.0.0.1:1234';
var body = {
userId : '123A',
comment: {
from: '123B',
content: 'I am a new generation of 123! :)'
}
};
var bodyToString = JSON.stringify(body);
$.ajax({url: serverURL + "/api/plates", dataType: "json", type: "PUT", data: bodyToString}).done(function (data) {
alert(data);
});
Allowing * origin access on your node server is a bad idea. http://docs.phonegap.com/en/1.9.0/guide_whitelist_index.md.html you can declare all domains to be supported by your app in phonegap itself, using element in cordova.xml. have a look at this Phonegap Cross-domain AJAX POST Request not working on Android
Edit
:
From comment below: if you need to allow access to any origin from chrome just for development purpose there is a plugin https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi