I'm using Express JS and Passport JS for my app.
I want to give a new user the opportunity to automatically login, once, by a specific URL. I can get the user from the database with the information from the URL, so I have an User object (with id, email, hashed password etc.) but I don't know how I can use passport to authenticate the user and login.
I tried executing below function with the user object I got from the database:
req.login(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + req.user.username);
});
source: http://passportjs.org/guide/login/
But that didn't work. Guess it's just because the user object contains the hashed password...
Anyone who ever tried this before and can tell me how it works?
Maybe https://github.com/yarax/passport-url strategy will be useful for you
Base logic is getting argument from url
UrlStrategy.prototype.authenticate = function(req, options) {
var self = this;
function verified(err, user, info) {
if (err) { return self.redirect(self.failRedirect); } // redirect in fail
self.success(user, info); // done callback
}
this._verify(req.query[this.varName], verified);
};
Full example here https://github.com/yarax/passport-url/blob/master/index.js
Heyo, so while #Rax Wunter is totally right, I just saw this question and wanted to say it is NOT A GOOD IDEA to do what you're doing here. You should never be passing a hashed password in a URL string ever. This is a really bad security concern.
What you should do instead is use something like a JSON Web Token (JWT). There are lots of libraries to help with this, but the basic flow goes something like this:
Wherever you are generating your URL, you'll instead generate a JWT that contains the user ID in it.
You'll then build a URL that looks like: https://somesite.com/?token=
On your https://somesite.com endpoint, you'll read in the token, validate it using the JWT library (and a shared secret variable), and this will confirm this token was unmodified (eg: you KNOW this user is who they claim to be).
This strategy above is really great because it means you can safely log someone in, in a trusted way, without compromising security or leaking a password hash at all.
There is not need of any additional module or passport-strategy for this. Adjust below code according to your use case;
router.get('/url/:token', (req, res) => {
User.findOne({token: req.params.token}, (err, user) => {
req.login(user, {}, function(err) {
if (err) { console.error(err); }
else return res.redirect("/home.html");
});
});
});
Related
I've written code with Passport.js for authentication purpose. While user logged into chrome and using same credentials user logged into another browser 'FF'.
As we all know that Passport.js store all details into req.users and req.session.passport.users. If from one browser user update some details how can we update into another browsers req object without logout?
Same kind of, If admin update user1 details and he already logged in than how that will affect?
Any clue?
As we all know that Passport.js store all details into req.users and
Not necessarily. passport.js does not store user details in req.user, but your passport.js integration code loads the user details from some backend storage and then puts it in the request object on every request.
So it is up to you to update the user in the backend and decide when to retrieve a new version ( instead of just deserializing jwt, for example ) on every request just as well.
Sample code from http://www.passportjs.org/docs/basic-digest/
passport.use(new BasicStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.validPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
This code is executed on every single request which means that on every request to the server your user is loaded from your database.
Even if you're working with multiple sessions in multiple browsers the result is the same. So it is up to you to handle when and how you want to update your user in your database.
Otherwise if you don't load your user from an external datasource but e.g. deserialize the whole user object from jwt ( which is not recommended unless you really understand what you're doing ) then you need to think of a synchronisation strategy e.g. check some updated flag in db or some cache on deserialization
I want to completely dissociate my client app from Parse server, to ease the switch to other Baas/custom backend in the future. As such, all client request will point to a node.js server who will make the request to Parse on behalf of the user.
Client <--> Node.js Server <--> Parse Server
As such, I need the node.js server to be able to switch between users so I can keep the context of their authentification.
I know how to authentificate, then keep the sessionToken of the user, and I ve seen during my research than the "accepted" solution to this problem was to call Parse.User.disableUnsafeCurrentUser, then using Parse.User.become() to switch the current user to the one making a request.
But that feels hackish, and I m pretty sure it will, sooner or later, lead to a race condition where the current user is switched before the request is made to Parse.
Another solution I found was to not care about Parse.User, and use the masterKey to save everything by the server, but that would make the server responsible of the ACL.
Is there a way to make request from different user other than thoses two?
Any request to the backend (query.find(), object.save(), etc) takes an optional options parameter as the final argument. This lets you specify extra permissions levels, such as forcing the master key or using a specific session token.
If you have the session token, your server code can make a request on behalf of that user, preserving ACL permissions.
Let's assume you have a table of Item objects, where we rely on ACLs to ensure that a user can only retrieve his own Items. The following code would use an explicit session token and only return the Items the user can see:
// fetch items visible to the user associate with `token`
fetchItems(token) {
new Parse.Query('Item')
.find({ sessionToken: token })
.then((results) => {
// do something with the items
});
}
become() was really designed for the Parse Cloud Code environment, where each request lives in a sandbox, and you can rely on a global current user for each request. It doesn't really make sense in a Node.js app, and we'll probably deprecate it.
I recently wrote a NodeJS application and had the same problem. I found that the combination of Parse.User.disableUnsafeCurrentUser and Parse.User.become() was not only hackish, but also caused several other problems I wasn't able to anticipate.
So here's what I did: I used
Parse.Cloud.useMasterKey(); and then loaded the current user by session ID as if it was a regular user object. It looked something like this:
module.exports = function(req, res, next) {
var Parse = req.app.locals.parse, query;
res.locals.parse = Parse;
if (req.session.userid === undefined) {
res.locals.user = undefined;
return next();
}
Parse.Cloud.useMasterKey();
query = new Parse.Query(Parse.User);
query.equalTo("objectId", req.session.userid);
query.first().then(function(result) {
res.locals.user = result;
return next();
}, function(err) {
res.locals.user = undefined;
console.error("error recovering user " + req.session.userid);
return next();
});
};
This code can obviously be optimized, but you can see the general idea. Upside: It works! Downside: No more use of Parse.User.current(), and the need to take special care in the backend that no conditions occur where someone overwrites data without permission.
Using Passport.js in Node, is there a way for me to allow one user to impersonate another? eg. as an Administrator in the application, I want to be able to log in as another user, without knowing their password.
Most simply, I would be satisfied if I could change the serialized user data (user ID) so when deserializeUser is called it will just assume the identity of the alternate user. I've tried replacing the value at req._passport.session.user and the value at req.session.passport.user but the net effect is just that my session seems to become invalid and Passport logs me out.
Passport provides a req.logIn method in case you want to do the authentication manually. You can use it to login any user even regardless of authentication.
Here's how you can use it. Have the Admin login normally, who'll have an isAdmin flag set.
Then place a middleware before passport.authenticate in your login route. This will login the new user based only on their username, if the currently logged in user isAdmin.
app.post('/login',
function forceLogin(req, res, next) {
if (!req.user.isAdmin) return next(); // skip if not admin
User.findOne({
username: req.body.username // < entered username
}, function(err, user) {
// no checking for password
req.logIn(user);
res.redirect('/users/' + user.username);
});
},
passport.authenticate('local'),
function(req, res) {
res.redirect('/users/' + req.user.username);
}
);
I have another way to impersonate, because:
I didn't want to mess with internals of authentication/passport like
session storage / logIn / etc. You must understand them really well
and also they are prone to change so I'd say it's not an option for
me.
Also, I'd like to still be able to tell if action is made from
superuser (impersonated) or normal user (not impersonated).
What I do is:
Have a route for user with superadmin role to impersonate, like /superadmin/impersonate?username=normaluser1 which sets req.user.impersonated.userid = normaluser1.userid
Then I have a middleware, which checks if user is superadmin and is impersonated:
if (req.user.isAdmin && req.user.impersonated) {
req.user.userid = req.user.impersonated.userid;
}
Also, I have found this to be a good article about user impersonation. Similar to my approach, and good for inspiration for building something similar.
The answer to your question is basically: no. The reason is this: the sessions library that is being used 99% of the time is signing the cookies, so if you tamper with the data the web server will reject it.
The way around this is to write your own passport authentication strategy that obviously doesn't do this, but I'm assuming you're talking about working with the built-in strategies here.
I'm trying to learn Express session and authentication handling.
For example:
app.post('/login', authCredentials, function(req, res) {
console.log("second")
});
function authCredentials(req, res, next) {
//this happens first
console.log(req.body) // => { username: etc, password: etc }
next();
}
My question is just how much should my authCredentials function do?
For example if the credentials are correct, I can do something like
res.redirect('/index'). Once I do that, however, what purpose does the second function have?
Other questions:
How would I handle invalid credentials?
If I make authCredentials just return true or false depending on the credentials, doesn't that break the middleware flow because it would never invoke next()?
Is it possible to access anything in authCredentials in the anonymous callback after it? Basically in the function(req, res) { }?
The answer depends on your authentication strategy i.e. are you using session identifiers, access tokens, etc.
In either case I suggest that you break out the credential exchange (aka login) from the authentication.
function usernamePasswordExchange(req,res,next){
var username = req.body.username;
var password = req.body.password;
callToAuthService(username,password,function(err,user){
if(err){
next(err); // bad password, user doesn’t exist, etc
}else{
/*
this part depends on your application. do you use
sessions or access tokens? you need to send the user
something that they can use for authentication on
subsequent requests
*/
res.end(/* send something */);
}
});
}
function authenticate(req,res,next){
/*
read the cookie, access token, etc.
verify that it is legit and then find
the user that it’s associated with
*/
validateRequestAndGetUser(req,function(err,user){
if(err){
next(err); // session expired, tampered, revoked
}else{
req.user = user;
next();
}
});
}
app.post('/login',usernamePasswordExchange);
app.get('/protected-resource',authenticate,function(req,res,next){
/*
If we are here we know the user is authenticated and we
can know who the user is by referencing req.user
*/
});
Disclaimer: I work at Stormpath and we spend a lot of time writing
authentication code :) I just wrote our newest library, stormpath-sdk-express,
which has a concrete implementation of my suggestions
You want to add your authCredentials middleware to every end point that needs authentication. app.post('/login') usually does not need any as you want to access this end point to actually get credentials in the first place.
When credentials are correct/valid you simply invoke next() and the workflow will jump to the next middleware or the actual end point. If there was an error, invoke next() with an error object like next(new Error('could not authenticate'); for instance. Add an error route to your general routing and the error will be handled there:
app.use(function(err, req, res, next) {
res.render('error', err);
});
Should be answered by now.
A middleware does not return a value. It either calls next() or ends the process differently by calling res.send().
There are different approaches to pass variables from one middleware to another. The most common is probably to attach the desired value to the req parameter.
authenticate is an asychronous function in the following example:
function authCredentials(req, res, next) {
authenticate(req.body, function(err, user) {
if (err) {
return next(err);
}
req.user = user;
next();
});
}
Hy and thanks in advance, So im working on a project, where part of the requirements, is to have a field where the user can insert is e-email, and then receive a custom url on his e-mail account, from there he can access the site. This is like the example of a "password-reset", where a custom url is generated and sent to u with a time-stamp validation. Im very new to nodejs, and my question here is if anyone has some type of guidlines to start doing this. My idea was to generate a sessionID, then generate a custom url, send the email, and then the users goes to the webpage. Im using express, and the whole site is already assembled, its just this feature tha is killing me! :(
I'm not sure what you need, but here is what I'd suggest (spoke about this on Reddit earlier).
// If you want the user to **have** to be a custom URL
req.param('userId', function(req, res, next) {
db.getUser(userId, function(e, usr) {
if (e) throw new Error(e);
req.user = usr;
});
});
req.all("*", function(req, res, next) {
if (!req.user) return res.redirect('/login');
});
// Rest of routes
req.get()
req.post()
That being said, you normally shouldn't have user login this way. Normally you would set the user in the session and validate it that way. Here's a good article on setting up sessions in Express.
If you do it this way, you would do something like this:
req.all("*", function(req, res, next) {
var userId = req.session('userid');
if (!userId) res.redirect('/login');
db.getUser(userId, function(e, usr) {
if (e) throw new Error(e);
if (!usr) return res.redirect('/login');
// Now the user is accessbile through its session
req.session.user = usr;
});
});
// Rest of routes
req.get()
req.post()
Password resetting requires what's called a nonce. This will be a small object in your DB that has a created date. You email them a link to your site that uses that nonce.
Whenever the route is hit that uses the password reset nonce, you look it up in the DB, verify it's new enough (within X hours or days), then give them access to the route that resets their password.
Your project requirements are pretty vague, so I'm not exactly sure what you need.
As of my understanding you want how to implement password reset functionality using expressjs.
Here are steps
1.
for forgot password
create an API
app.post('/forgotpassword',function(req,res){
var email = req.body.email;
// validation
// your custom url creation logic here
// someurl/:resetpasswordtoken
// store this in user data
// for this I'll suggest to use any unique string creation logic*
}
to show reset password page
app.get('/someurl/:resetpasswordtoken, function(req,res) {
//check token exist
// render the page for reset like current passwor,new password
}
Action for reset password
app.post('/someurl/:resetpasswordtoken , function(req,res){
var currentPwd = //get current pwd
var newPwd = //get new pwd
//check token
//then reset password for user
}