I finally got done replacing an everyauth/ mongoose-auth login system with a passport implementation. I'm using this purely for local username/ password logins, so I'm also utilizing the passport-local module as well.
I know from looking through a few examples, I found Passport auto-assigns a couple req helpers. I've not been able to find a full list of variables it puts there though, a couple I've found are req.isAuthenticated() and the req.user variables.
Is there a full list provided anywhere online? Just interested in my options available in routes/ views. I can keep trolling through examples, but it would be nice if there was a reference somwhere.
For a Connect/Express application,
1.var passport = require('passport');
The following four helper functions are added to http.IncomingMessage.prototype(i.e., the request object's prototype):
login/logIn(user, [options,] done)
logout/logOut()
isAuthenticated() - i.e. whether req.user exists.
isUnauthenticated()
If a user is authenticated successfully, usually a callback function done(null, user) is called. This callback function then calls req.logIn() which in turn calls serializeUser() to store the user id as req._passport.session.user.
The req.logOut() function deletes req._passport.session.user.
2.app.use(passport.initialize());
Get the passport info from current session and store it as req._passport.session(i.e., req.session['passport']).
3.app.use(passport.session());
Check whether req._passport.session.user exists, that is, whether the user id is stored in current session. If yes, call deserializeUser() to get the user object which will be stored as req.user.
Related
Alrigh, so I have set up an entire passport local authorization, every thing works pretty perfectly, except I can't seem to wrap my head around one issue with passport.js.
I am authorizing users through sessions (they work fine), however I can't seem to extract the user info from that session, although if I manually check my session db, for every session there is a userid (which links to the user).
Also the deserialize functions seem to return the user and the log is showing the correct user.
Now the problem is that I can't seem to pass this user<->session info anywhere in my routes.
The issue that I seem to have with this is that people that are logged in, are authorized, but they can fiddle with the request body as much as they like, doing things as posting messages in their name, logging them out, ...
Code example:
router.post('/games/:id/verify', isAuthenticated, function(req, res){
log('#POST verify for game with id: ' + req.params.id);
gameController.postVerify(req.params.id, req, res);
});
In this code, it just checks if a user is logged in, if possible, I want to check which user is logged in to that session, so that he cannot verify this game if he was not part of it.
Let's say user A, B were part of the game and need to verify it. This function allows user C who is logged in to verify for them, because this function only checks if the user is logged in.
If I can pass the logged in user (user C in the test case) to the gameController, I can write my own checks in there and throw them out.
Passport will populate req.user when authentication has succeeded. It will be populated by the data provided by deserializeUser, which generally is a database record of the user.
You can use that information to limit other database queries/checks/etc to make sure that the logged-in user is allowed to access particular information.
I am using node/express with passport in my development. I came across an article which says:
Express loads the session data and attaches it to the req. As passport stores the serialised user in the session, the serialised user object can be found at req.session.passport.user.
But to my surprise, the value for sessionID stores in the browser cookies remain the same before and after login. So where does the serialised user object is stored?
I thought that it was stored in the user sessionid cookie initially but it seems that this is not the case as I still can access my user object with req.session.passport.user
So where does the serialised user object is stored?
In Short
The serialized user object is stored in req.user by PassportJS taken from req.session.passport.user (which is is populated by Express) with the help of Passport's deserializeUser method.
Express adds the id of the session object into a cookie on user's browser, which is sent back to express in a header on every request. Express then takes the id from the header and search the session store (i.e. Mongo or whatever) and find the entry and load it to req.session.
PassportJS uses the content of req.session to keep track of the authenticated user with the help of serializeUser and deserializeUser methods (for more information on workflow of serializeUser and deserializeUser see my answer in this SO question).
Express is responsible for creating the session. when does the sessions gets created? That is when Express do not detect a session cookie. So the order in which you organize your session and passport configs in your app or server.js file is very important. If you declare your session and passport configs above static directory configs then all requests for static content will also get a session, which is not good.
See my answer to this SO question, where I have mentioned about static content access as well as how to selectively apply passport to certain routes, rather than default (you might not need to authenticate all the routes - hence you could avoid unnecessary session store lookup and de-serialization by attaching session only to requests that map to secure URLS see below).
//selectively applying passport to only secure urls
app.use(function(req, res, next){
if(req.url.match('/xxxx/secure'))
passport.session()(req, res, next)
else
next(); // do not invoke passport
});
There is one amazing tutorial that I highly recommend you to read up if you want to understand the workflow of PassportJS.
You can look at the sessionID in the cookie as a key to a database where the session data is stored. Depending on what session handler you use with express, and what storage policy you use the data will be stored in different ways. This means that the sessionID can be the same value both before login, after a successful login, and even after a user logs out.
If you use express-session with MemoryStore the data will be saved in the memory of the node process, indexed on the sessionID. Look here for initialization of the store and here for storing of the data.
You could create a store where the data is serialized to the cookie, but none such are listed in the compatible session stores.
As per this article
http://toon.io/understanding-passportjs-authentication-flow/
it looks as though PassportJS/Express store the logged in user in two places
req.user
and
req.session.passport.user
why both? which one should I use? When I logout with passport, does it destroy both req.user and req.session.passport.user?
You should always, always use req.user in your own code -- this is important because if you use req.session.passport.user, you're essentially pulling user information out of a session cookie (which may be outdated).
It's always best to rely on req.user as opposed to cookie data directly, as depending on your implementation, that information might be out of date.
And to answer your question: if you log a user out, both req.session and req.user will no longer be available.
What do the passport.js functions passport.serializeUser and passport.serializeUser do? Is this an example of serialization as it is described on wikipedia: http://en.wikipedia.org/wiki/Serialization
Yep.
These allow the user's data to be saved and retrieved from a session store. This could be memory, redis, or any other database.
If you like reading the source, you will see that passport.session is involved as it will restore login state from a session and the deserializeUser gets the user information from that.
The code that follows after Authenticator.prototype.session defines the serializeUser and deserializeUser methods that let us add our own serializers/deserializers.
Under a variety of circumstances, Facebook's internal AccessToken (used for various features in the Facebook API and other cases) may become invalid. For example, if a user changes her password between sessions of using an application that relies on Facebook Login. There are a few other cases as well.
What happens, however, is that your application essentially crashes, with an error like this: data={"error":{"message":"Error validating access token: Session does not match current stored session. This may be because the user changed the password since the time the session was created or Facebook has changed the session for security reasons.", "type":"OAuthException", "code":190, "error_subcode":460}}.
Passport's Facebook Strategy uses the AccessToken, and it's available to an app as soon as a user is logged in / authenticated via Passport. The problem, however, is what to do when the above error is encountered. Facebook gives a convoluted re-auth flow as an example in PHP, but the general sense is that you need to re-authorize your app with Facebook.
The question is, even when removing the Facebook app from your Facebook page, and forcing the application relying on Facebook Login to re-authorize itself, it seems that Passport + Facebook Strategy is still picking up the last existing AccessToken from the browser's session storage. (At least that's what I'm seeing with Mozilla/Fx 26). I have re-authorized my app several times, but when debugging and looking at what Passport returns, I always get back the same invalid AccessToken. Seems like if an AccessToken exists in session-storage, Passport picks that up instead of getting a new one from Facebook.
So is there a way - within Passport + Facebook Strategy - to essentially ignore or override any stored AccessToken and always request a new one from Facebook, in the event of this kind of error? Not at all clear how to make that happen. Thanks for the help.
Update: The sample code for invoking the strategy has refreshToken as a parameter; what does this do? Is there a possible solution with this parameter?
passport.use(new FacebookStrategy(
{
...
},
function(accessToken, refreshToken, profile, done)
{
I found the answer to my question, and will leave it up in case anyone else encounters the same issue.
Passport, in its VerifyCallback function, passes the AccessToken to the application. The recommendation (tacit or otherwise) is to of course save this AccessToken as part of the user's persisted record (say, a MongoDB document). It'll be needed when making subsequent calls to the Facebook API, and though it can probably be safely retrieved from the request.user object passed around through the Express middleware, having your own local copy probably makes sense.
Now, when you're done authenticating the user via Passport, you still will pull up your user's persisted record to get other user data. Passport documentation features a generic function called Users.findOrCreate() to serve as a model/prototype of this function for you to implement. And here's where the issue lies: If you find a user (one already exists) via this function, you'll be using that record throughout your app. And if that record also holds an AccessToken, and that AccessToken has changed, then of course you'll be in trouble: Passport/Facebook is passing you a new AccessToken, but you're using an outdated one.
So the simple fix is this: If you've implemented a Users.findOrCreate() function to persist a user and rely on this to retrieve a user's set of data - and that record also stores the AccessToken - then make sure you check the current (old) AccessToken to the one Passport/Facebook is passing you in the VerifyCallback when a user has just been authenticated; if the two are different, update the user's persisted record and use this new Token.