Merge pull request #2 from spotify/add-state

Add state generation and check
This commit is contained in:
Michael Thelin 2014-07-01 09:51:53 +02:00
commit 28d3943eae
4 changed files with 178 additions and 107 deletions

View file

@ -10,17 +10,39 @@
var express = require('express'); // Express web server framework
var request = require('request'); // "Request" library
var querystring = require('querystring');
var cookieParser = require('cookie-parser');
var client_id = '03ffe0cac0a0401aa6673c3cf6d02ced'; // Your client id
var client_secret = 'a57c43efb9644574a96d6623fb8bfbc2'; // Your client secret
var redirect_uri = 'http://localhost:8888/callback'; // Your redirect uri
/**
* Generates a random string containing numbers and letters
* @param {number} length The length of the string
* @return {string} The generated string
*/
var generateRandomString = function(length) {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
var stateKey = 'spotify_auth_state';
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(express.static(__dirname + '/public'))
.use(cookieParser());
app.get('/login', function(req, res) {
var state = generateRandomString(16);
res.cookie(stateKey, state);
// your application requests authorization
var scope = 'user-read-private user-read-email';
res.redirect('https://accounts.spotify.com/authorize?' +
@ -28,14 +50,27 @@ app.get('/login', function(req, res) {
response_type: 'code',
client_id: client_id,
scope: scope,
redirect_uri: redirect_uri
redirect_uri: redirect_uri,
state: state
}));
});
app.get('/callback', function(req, res) {
// your application requests refresh and access tokens
var code = req.query.code;
// after checking the state parameter
var code = req.query.code || null;
var state = req.query.state || null;
var storedState = req.cookies ? req.cookies[stateKey] : null;
if (state === null || state !== storedState) {
res.redirect('/#' +
querystring.stringify({
error: 'state_mismatch'
}));
} else {
res.clearCookie(stateKey);
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
form: {
@ -71,8 +106,14 @@ app.get('/callback', function(req, res) {
access_token: access_token,
refresh_token: refresh_token
}));
} else {
res.redirect('/#' +
querystring.stringify({
error: 'invalid_token'
}));
}
});
}
});
app.get('/refresh_token', function(req, res) {

View file

@ -89,14 +89,19 @@
var params = getHashParams();
var access_token = params.access_token
refresh_token = params.refresh_token;
refresh_token = params.refresh_token,
error = params.error;
if (error) {
alert('There was an error during the authentication');
} else {
if (access_token) {
// render oauth info
oauthPlaceholder.innerHTML = oauthTemplate({
access_token: access_token,
refresh_token: refresh_token
});
if (access_token) {
$.ajax({
url: 'https://api.spotify.com/v1/me',
headers: {
@ -110,6 +115,7 @@
}
});
} else {
// render initial screen
$('#login').show();
$('#loggedin').hide();
}
@ -128,7 +134,7 @@
});
});
}, false);
}
})();
</script>
</html>

View file

@ -62,6 +62,8 @@
<script>
(function() {
var stateKey = 'spotify_auth_state';
/**
* Obtains parameters from the hash of the URL
* @return Object
@ -76,6 +78,21 @@
return hashParams;
}
/**
* Generates a random string containing numbers and letters
* @param {number} length The length of the string
* @return {string} The generated string
*/
function generateRandomString(length) {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
var userProfileSource = document.getElementById('user-profile-template').innerHTML,
userProfileTemplate = Handlebars.compile(userProfileSource),
userProfilePlaceholder = document.getElementById('user-profile');
@ -86,12 +103,14 @@
var params = getHashParams();
var access_token = params.access_token;
oauthPlaceholder.innerHTML = oauthTemplate({
access_token: access_token
});
var access_token = params.access_token,
state = params.state,
storedState = localStorage.getItem(stateKey);
if (access_token && (state == null || state !== storedState)) {
alert('There was an error during the authentication');
} else {
localStorage.removeItem(stateKey);
if (access_token) {
$.ajax({
url: 'https://api.spotify.com/v1/me',
@ -115,6 +134,9 @@
var client_id = '03ffe0cac0a0401aa6673c3cf6d02ced'; // Your client id
var redirect_uri = 'http://localhost:8888/'; // Your redirect uri
var state = generateRandomString(16);
localStorage.setItem(stateKey, state);
var scope = 'user-read-private user-read-email';
var url = 'https://accounts.spotify.com/authorize';
@ -122,10 +144,11 @@
url += '&client_id=' + encodeURIComponent(client_id);
url += '&scope=' + encodeURIComponent(scope);
url += '&redirect_uri=' + encodeURIComponent(redirect_uri);
url += '&state=' + encodeURIComponent(state);
window.location = url;
}, false);
}
})();
</script>
</html>

View file

@ -5,8 +5,9 @@
"version": "0.0.1",
"main": "app.js",
"dependencies": {
"cookie-parser": "1.3.2",
"express": "~4.0.0",
"request": "~2.34.0",
"querystring": "~0.2.0"
"querystring": "~0.2.0",
"request": "~2.34.0"
}
}