Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly use Passport.js?

I am using :

  • Node.js
  • Express 4.0
  • Passport.js
  • Google OAuth 2 for Authentication

For each user, I store in a MySQL DB (I don't have the choice regarding this technology) some info from his Google Profile (email etc...), access & refresh tokens, and also additionnal info that the user provides when he registers on my app.

I have seen different uses of passport.js, specifically regarding how that info is stored in session.

  1. On passport.js's configure page, I don't really understand the point of the following block of code :

    passport.deserializeUser(function(id, done) {
      User.findById(id, function(err, user) {
        done(err, user);
      });
    });
    

    Basically, each time the user makes a request, or visits a page, there's a request to the DB and information is retrieved. What is the point ? It slows the app a lot. Shouldn't the info from the DB be retrieved when serializeUser is called (ie. when the info is stored in session) ?

  2. I have read that storing too much info in session can slow the app. What is "too much" ? How much will it slow the app ? Does someone know if there are tests somewhere ? My app's pages require a different set of data about my user (for example, the homepage will only need his name whereas the profile page will need everything, another page will need to know what cars he owns etc...). Should I store all that info in session when passport.authenticate checks if the user exists in the DB (thus limiting read-requests to the DB to approximately one), or only store in session his id and have my pages make additionnal requests to the DB when necessary ?

  3. Another issue I have : in the registration process, I first have the user log in on his Google Account, I store his profile's details somewhere, have him fill a form for additionnal info, and then I insert everything in the DB. The problem is I don't know how to properly store his Google Account details until they are inserted into the DB. For the moment, I store them in session, and then delete that when the insertion is successful. More specifically, when no existing user is found in my DB, I do, in my passport.authenticate callback:

    return done(null,false,userInfo);
    

    Thus, the user is not authenticated and I have 2 issues : I have to store that userInfo somewhere until the user is registered and I have to log him "manually" using req.login() after the registration is complete.

    Should I allow him to be authenticated as soon as he logs in on his Google Account ? Wouldn't that cause security issues for me if he does not complete his registration ?

  4. Lastly, I have read about using Reddis. Would that help me with these issues ?

Thank you very much !

like image 726
Waldo Jeffers Avatar asked Dec 26 '22 07:12

Waldo Jeffers


1 Answers

1) serializeUser is filtering the data and storing it in the session cookie. generally store less in the cookie if you can. You are going to call the db for data about the user anyways so you can just store an ID used to retrieve and reconstruct the user, as seen in deserializeUser.

Request coming in the cookie is provided to the server by the client, the server deserializes the cookie into data, either decrypting cookie content or retrieving user data from the db. Then response headed out the server serializes the client data, scraping off things you wouldn't store in the cookie and putting them in the db, just leaving an id in the cookie.

if you are doing encryption then this can easily be screwed up when you want to scale by running multiple machines who each need to be able to decrypt the data (not really hard, but unnecessary complexity)

Having unencrypted data just lying in the cookie isn't the best, and besides anything in the cookie can add that inkling of extra bandwidth usage for the user.

2) The database calls should be very fast, if they aren't you are going to have a suffering user experience elsewhere anyways. In other words, my strong opinion is that there is an overwhelming argument for staying away from cookies.

consider that cookies are sent with each request; it would be smarter to, instead of shoving data into the session and having it add overhead, have the user data load up temporarily (cached) for a bit after the user makes a request, and then have neither database calls nor overhead from the cookie while the user is actively on your site.

honestly you should be fine at first without caching. Focus on getting your app up with minumum complexity. This way you can modify it according to user feedback faster and have fewer mistakes.

3) When I played with passport I had a similar issue. I would let passport do its job and grant passport-level-verification to the user (so yes they are logged in), then do more data collection separately. If you are concerned about security then make this passport-level verification not fully logged in, and require more data before upgrading to fully logged in.

I could be very off the mark with this one, but that's my recommendation.

4) Redis is good for times when you have multiple node instances and want to store something in memory (say a counter, or that cached user data). This way you don't have variables in the node code holding onto cached data about a user, which another node instance can't take advantage of when the user comes back and the load balancer shoots them to a different instance. http://www.ourdailycodes.com/2013/09/redis-when-should-i-use-it.html

EDIT: I should add that session uses a cookie, but only gives the user a unique token the server understands, so that the server can re-gather the user's session data when a connection is received with an accompanying session token. My understanding is that this is the generally correct way for Session to work... but that it varies by implementation (Someone correct me if I am wrong here).

like image 188
Catalyst Avatar answered Dec 28 '22 11:12

Catalyst