I am currently experimenting with OAuth2 to develop a mobile application built entirely in JavaScript that talks to a CakePHP API. Take a look at the following code to see how my app currently looks (please note that this is an experiment, hence the messy code, and lack of structure in areas, etc..)
var access_token,
refresh_token;
var App = {
init: function() {
$(document).ready(function(){
Users.checkAuthenticated();
});
}(),
splash: function() {
var contentLogin = 'Log in';
$('#app').html(contentLogin);
},
home: function() {
var contentHome = '
$('#app').html(contentHome);
}
};
var Users = {
init: function(){
$(document).ready(function() {
$('#login').live('click', function(e){
e.preventDefault();
Users.login();
});
$('#logout').live('click', function(e){
e.preventDefault();
Users.logout();
});
});
}(),
checkAuthenticated: function() {
access_token = window.localStorage.getItem('access_token');
if( access_token == null ) {
App.splash();
}
else {
Users.checkTokenValid(access_token);
}
},
checkTokenValid: function(access_token){
$.ajax({
type: 'GET',
url: 'http://domain.com/api/oauth/userinfo',
data: {
access_token: access_token
},
dataType: 'jsonp',
success: function(data) {
console.log('success');
if( data.error ) {
refresh_token = window.localStorage.getItem('refresh_token');
if( refresh_token == null ) {
App.splash();
} else {
Users.refreshToken(refresh_token);
}
} else {
App.home();
}
},
error: function(a,b,c) {
console.log('error');
console.log(a,b,c);
refresh_token = window.localStorage.getItem('refresh_token');
if( refresh_token == null ) {
App.splash();
} else {
Users.refreshToken(refresh_token);
}
}
});
},
refreshToken: function(refreshToken){
$.ajax({
type: 'GET',
url: 'http://domain.com/api/oauth/token',
data: {
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: 'NTEzN2FjNzZlYzU4ZGM2'
},
dataType: 'jsonp',
success: function(data) {
if( data.error ) {
alert(data.error);
} else {
window.localStorage.setItem('access_token', data.access_token);
window.localStorage.setItem('refresh_token', data.refresh_token);
access_token = window.localStorage.getItem('access_token');
refresh_token = window.localStorage.getItem('refresh_token');
App.home();
}
},
error: function(a,b,c) {
console.log(a,b,c);
}
});
},
login: function() {
$.ajax({
type: 'GET',
url: 'http://domain.com/api/oauth/token',
data: {
grant_type: 'password',
username: $('#Username').val(),
password: $('#Password').val(),
client_id: 'NTEzN2FjNzZlYzU4ZGM2'
},
dataType: 'jsonp',
success: function(data) {
if( data.error ) {
alert(data.error);
} else {
window.localStorage.setItem('access_token', data.access_token);
window.localStorage.setItem('refresh_token', data.refresh_token);
access_token = window.localStorage.getItem('access_token');
refresh_token = window.localStorage.getItem('refresh_token');
App.home();
}
},
error: function(a,b,c) {
console.log(a,b,c);
}
});
},
logout: function() {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
access_token = window.localStorage.getItem('access_token');
refresh_token = window.localStorage.getItem('refresh_token');
App.splash();
}
};
I have a number of questions relating to my implementation of OAuth:
1.) Apparently storing the access_token in localStorage is bad practice and I should instead be using cookies. Can anyone explain why? As this isn't anymore secure or less secure as far as I can tell, as the cookie data wouldn't be encrypted.
UPDATE: According to this question: Local Storage vs Cookies storing the data in localStorage is ONLY available on the client-side anyways and doesn't do any HTTP request unlike cookies, so seems more secure to me, or least doesn't seem to have any issues as far as I can tell!
2.) Relating to question 1, use of a cookie for expiration time, would equally be pointless to me, as if you look at the code, a request is made on app start to get the user info, which would return an error if it had expired on the server end, and require a refresh_token. So not sure of benefits of having expiry times on BOTH client and server, when the server one is what really matters.
3.) How do I get a refresh token, without A, storing it with the original access_token to use later, and B) also storing a client_id? I've been told this is a security issue, but how can I use these later, but protect them in a JS-only app? Again see the code above to see how I have implemented this so far.