Reputation: 1380
My mobile hybrid app uses an expressJS server as the backend to proxy requests to parse.com via the REST API. I also use express for my own user authentication with an SSO provider. I've followed this tutorial and modified the approach a bit to work for my own setup (not using CloudCode, also not authenticating with GitHub). I'm also using the newish Revokable Sessions that came about earlier this year (March 2015?) Essentially the tutorial and my auth approach can be boiled down to doing the following on a remote backend (ExpressJS / CloudCode):
Login As User to Obtain Session Token
Create a new user if username doesn't already exist, and then continue
Create a new random password for the user (update the users password with masterKey)
With new password, log in as the user to generate the Parse sessionToken
Pass back the sessionToken to the client app
This all works fine, it seems to be the 'approach' for logging in with third-party authentication providers.
Problem is that each time my user logs in, the sessionToken essentially is re-created (as in, it destroys the old and creates a new token). I can see this in the dataBrowser as the session objectId is different. Also, and the main problem is that my user may have logged in on other devices, or on the web app, and essentially each time a user switches devices, the session token is invalidated on the other devices. Returning to that device then requires another login.
The new enhance session blog post mentions that the new revokable sessions provides for 'unique sessions' per device, however from my experience this doesn't seem to be working for users logging in over the REST API from my express backend. Perhaps this unique session would only work if the app itself was communicating to parse and thus would be able to pass along an installationId to distinguish the different devices.
I've posted my authentication code below, the parse object is from this npm parse library
upsertUser function:
/**
* This function checks to see if this user has logged in before.
* If the user is found, update their password in order to 'become' them and then return
* the user's Parse session token. If not found, createNewUser
*/
exports.upsertUser = function(ssoData, deferred) {
var userCreated = (typeof deferred != "undefined") ? true : false;
var deferred = deferred || q.defer();
var query = {
where: {username: ssoData.uid.trim()}
};
// set masterKey
parse.masterKey = parseConfig.MASTER_KEY;
// find existing user by username
parse.getUsers( query, function (err, res, body, success) {
if ( body.length ) {
var userId = body[0].objectId;
var username = body[0].username;
var password = new Buffer(24);
_.times(24, function (i) {
password.set(i, _.random(0, 255));
});
password = password.toString('base64');
parse.updateUser(userId, {password: password}, function (err, res, body, success) {
if ( typeof body.updatedAt != 'undefined' ) {
console.log('user update at: ', body.updatedAt);
parse.loginUser(username, password, function (err, res, body, success) {
deferred.resolve( body.sessionToken );
});
}
});
} else if ( userCreated === false ) {
console.log('object not found, create new user');
self.createNewUser(ssoData, deferred);
} else {
deferred.resolve();
}
});
return deferred.promise;
}
createNewUser function:
/**
* This function creates a Parse User with a random login and password, and
* Once completed, this will return upsertUser.
*/
exports.createNewUser = function(ssoData, deferred) {
// Generate a random username and password.
var password = new Buffer(24);
_.times(24, function(i) {
password.set(i, _.random(0, 255));
});
var newUser = {
username: ssoData.uid,
password: password.toString('base64'),
};
// Sign up the new User
parse.createUser(newUser, function(err, res, body, success) {
if (err) {
console.log('new parse user err', err)
}
if (typeof body.sessionToken != "undefined") {
self.upsertUser(ssoData, deferred);
} else {
deferred.resolve();
}
});
}
Any ideas how I can avoid invalidating sessionTokens upon subsequent logins?
Upvotes: 0
Views: 719
Reputation: 1380
Shoot, it seems there's a toggle on the settings page that I missed:
Revoke existing session tokens when user changes password
Simple as that i guess ;-) Still, I don't think I'll get unique sessions across devices.
Upvotes: 4