Prevent user authentication after signup with passport - node.js

I have set up a login/signup interface and mechanism using passport and express.js. The problem that I have is that after the signup of the user, we are redirected to the login page, but we can eventually change the URL and enter immediately in the user profile, but this is of course not expected and wanted. I would like that the user is not authenticated after the signup and that he needs to enter his/her credentials manually in the login page before entering to its profile.
router.get('/', isAuthenticated, function(req, res) {
res.render('library', {
// passing the id of and username the connecting user to the dust
userid: req.user._id,
username: req.user.userName
});
});
router.get('/library', isAuthenticated, function(req, res) {
res.render('library', {
// passing the id of and username the connecting user to the dust
userid: req.user._id,
username: req.user.userName
});
});
/* GET login page. */
router.get('/login', function(req, res) {
// Display the Login page with any flash message, if any
res.render('login', {
message: req.flash('message')
});
});
/* Handle Login POST
password.authenticate is used to delegate the authentication
to the login strategy when a HTTP POST is made to /login.
*/
router.post('/login', passport.authenticate('login', {
successRedirect: '/library',
failureRedirect: '/',
failureFlash: true
}));
/* GET Registration Page */
router.get('/signup', function(req, res) {
res.render('signup', {
message: req.flash('message')
});
});
/* Handle Registration POST
password.authenticate is used to delegate the authentication
to the signup strategy when a HTTP POST is made to /signup.
*/
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/login',
failureRedirect: '/signup',
failureFlash: true
}));
and the isAuthenticated function/middleware is defined as follows
var isAuthenticated = function(req, res, next) {
// if user is authenticated in the session, call the next() to call the next request handler
// Passport adds this method to request object. A middleware is allowed to add properties to
// request and response objects
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('/login');
}
}
What am I doing wrong?
Basically, after signup, I have a button which redirects to /, and if we are redirected to library (like it's happening to me), then the user should already be authenticated, but I don't want this...

There's at least two solutions to this:
Add session: false to the config object you pass to passport.authenticate('signup', {...}) as described in the passportjs documentation.
Don't use passport for signups. The main use case for passport is for authenticating (and establishing sessions) and DIY signup logic is more or less just a matter of copying the code from your signup passport middleware.

Related

What's the difference between req.isAuthenticated() and passport.authenticate() in passport?

I am a beginner in programmation and experimenting the authentication process through node.js, express and mongoDB. I have used passport, passport-local and passport-local-mongoose to create a login/logout for users.
When my authentication succeed, user is redirect to my index page which show his/her name.
But I have a question… What is the difference between req.isAuthenticated() and passport.authenticate() ?
In my main.js, I have directly placed my req.user in the core of my session :
const passport = require('passport');
const expressSession =require('express-session');
const cookieParser = require('cookie-parser');
const connectFlash = require('connect-flash')
const localStrategy = require('passport-local').Strategy;
app.use(cookieParser("SecretStringForCookies"));
app.use(
expressSession({
secret : "SecretStringForCookies",
cookie : {
maxAge: 2000000
},
resave : false,
saveUninitialized : false
}))
app.use(passport.initialize());
app.use(passport.session());
//Serializing and deserializing user for checking login status in cookie
const User = require('./models/allUsers');
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(connectFlash());
app.use((req, res, next) => {
res.locals.flashMessages = req.flash();
res.locals.currentUser = req.user;
next();
});
For my authentication to succeed, I have used the following code in a UserController.js page :
module.exports = {
authentication : passport.authenticate("local", {
failureRedirect: "/login",
successRedirect: "/index",
successFlash : { type: 'success_msg', message: 'Welcome !' },
failureFlash : { type: 'error_msg', message: 'Your email and/or password are wrong, try again !' }
}),
isAuthenticatedUser : (req, res, next) => {
if(req.isAuthenticated()) {
next();
}
res.redirect = "/login";
},
}
My routes regarding the authentification :
const express = require('express');
const router = express.Router();
const userController = require('./userController');
router.post('/login', userController.authenticate, userController.isAuthenticatedUser);
router.get("/logout", userController.isAuthenticatedUser, (req, res)=> {req.logout(), res.redirect("/")});
router.get('/index');
My HTML :
<nav class="nav-links">
<% if(currentUser) { %>
<ul>
<li><%= currentUser.name %></li>
<li>Logout</li>
<li>Home</li>
</ul>
<% } %>
</nav>
However, my login authentication process seems to work fine with just only passport.authenticate() and my routes for login/logout doesn’t seem to need my function about req.isAuthenticated().
Sorry if my question seems dumb or weird but I am really confused about its purpose…
Could you please give me some advice ?
Thank you in advance for your help !
passport.authenticate() method extracts user credentials from request object and passes them to the authentication function which you use to authenticate the process,
passport.use(new LocalStrategy(
function(username, password, done) { // this is an authentication function
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
By default, when authentication succeeds, the req.user property is set to the authenticated user, a session is established, and the next function in the stack is called.
req.isAuthenticated() method checks if the user is already authenticated by the authentication function or not, for example, if you have an admin dashboard page and you want to ensure that only authenticated users can access this page, therefore you use req.isAuthenticated() method to ensure that the user who sends the request is already authenticated by the authentication function.
module.exports= (req,res, next)=>{
if(req.isAuthenticated()){ //checks whether user
//is authenticated by the passport.authenticate() method
next();
}
res.redirect('/login');
}
The req.isAuthenticated() command returns whether the user is logged in or not, and the other ensures that the user is logged in.

How to redirect on a custom page after login?

I'm using PassportJS for handle the access to my application, suppose that the user has logged in, and suppose that these urls:
Login
Register
Welcome
need to redirect the user on dashboard url, only if the user has logged in, how can I do?
This is my authentication middleware:
module.exports = {
ensureAuthenticated: function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.render('index/forbidden');
}
};
Example:
User go to login
No session
Stay on the page
(already works)
User go to login
Already logged in
Redirect to dashboard
You can create another middleware to redirect if logged in and add it to the routes that don't need login. You are basically doing the opposite.
module.exports = {
ensureAuthenticated: function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.render('index/forbidden');
},
ensureNOTAuthenticated: function(req, res, next){
if(req.isAuthenticated()){
return res.redirect('/dashboard')
}
return next();
}
};
For routes that need auth:
app.get('/dashboard', ensureAuthenticated, (req,res)=>{...});
For routes that dob't need auth:
app.get('/login', ensureNOTAuthenticated, (req,res)=>{...});

Redirecting to original url after authentication in PassportJS

I am trying to access the URL http://localhost:3000/users#/WyCrYc28r/foo/1414585518343, but a user needs to be authenticated before he/she could access that path as shown below:
app.get('/users', isLoggedIn, function (req, res) {
req.session.user = req.user;
res.cookie('uid', req.session.passport.user)
.render('users', { title: 'The Foo Machine', user: req.user });
});
The isLoggedIn middleware is used as following for finding out if the user is authenticated:
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/login');
}
Anf following is how a request to login is being handled using PassportJS:
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/users',
failureRedirect: '/login',
failureFlash: true
}));
But I do not want the user to go to /users after logging in successfully. I want the user to go back to the its original URL (http://localhost:3000/users#/WyCrYc28r/foo/1414585518343) that he/she was trying to access.
I am using the LocalStrategy for authentication/autheorization using PassportJS.
Could somebody help me with it?

User is not authenticated after res.redirect()

I'm having an issue where despite logging in successfully (as evidenced by the successRedirect handler triggering), the request is still not authenticated, so my authentication middleware sends us back to the login page again.
My routes look as follows:
// ROUTES
module.exports = function(app, passport) {
app.get('/home', isLoggedIn, function(req, res) {
res.sendfile('imconfusedindex.html'); // this never gets sent.
});
app.post('/login', passport.authenticate('ldap-auth', {
successRedirect: '/home',
failureRedirect: '/login'
}));
}
// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated, we'll all float on OK
if (req.isAuthenticated()) {
return next();
}
// otherwise, redirect them to the login page
res.redirect('/login');
}
And my passport configuration looks like this:
passport.serializeUser(function(user, done) {
done(null, user.user_id);
});
passport.deserializeUser(function(id, done) {
connection.query("select * from users where user_id = " + id, function(err, rows) {
done(err, rows[0]);
});
});
passport.use('ldap-auth', new LocalStrategy(
function(username, password, done) {
done(null, {user_id: 2, username: 'bob'});
})
);
As you can see in the passport configuration, I'm returning a dummy user every time. Doing more debugging shows that the request is being authenticated, but after the redirect, it is no longer authenticated.
Unsure what to do, any ideas would be appreciated.
Sigh I'm really stupid...the answer lurked in another question but when I read it I didn't quite put 2 and 2 together.
I'm lacking an express-session (didn't even include my server config here so even harder to debug). As soon as I set up an session, it worked.
In case someone else has this same issue, make sure that in your app config, you include something like:
var session = require('express-session');
app.use(session({secret: 'dontderplikeme'});
When you add in passport and include app.use(passport.session()), this is the session that it will be using to store credentials into.

how to send json as a response after passport authenticationin node.js

I am trying this git example.
Which works well when I integrated it with my project, but what I want to achieve is to send json as a response to the client/request, instead of successRedirect : '/profile' & failureRedirect : '/signup'.
Is it possible to send a json, or is there some other methods to get the same?
Any help will be appreciated,TU
here I modified my code to send json as a response
// process the signup form
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/successjson', // redirect to the secure profile section
failureRedirect : '/failurejson', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
app.get('/successjson', function(req, res) {
res.sendfile('public/index.htm');
});
app.get('/failurejson', function(req, res) {
res.json({ message: 'hello' });
});
You can use passport's authenticate function as route middleware in your express application.
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
// Then you can send your json as response.
res.json({message:"Success", username: req.user.username});
});
By default, if authentication fails, Passport will respond with a 401 Unauthorized status, and any additional route handlers will not be invoked. If authentication succeeds, the next handler will be invoked and the req.user property will be set to the authenticated user.
Create new route, e.g.: /jsonSend with res.json in it and make successRedirect: '/jsonSend'. That should do it.
There is an official Custom Callback documentation:
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
https://github.com/passport/www.passportjs.org/blob/master/views/docs/authenticate.md
Use passport as a middleware.
router.get('/auth/callback', passport.authenticate('facebook'),
function(req, res){
if (req.user) { res.send(req.user); }
else { res.send(401); }
});
// process the signup form
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/successjson', // redirect to the secure profile section
failureRedirect : '/failurejson', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
app.get('/successjson', function(req, res) {
res.sendfile('public/index.htm');
});
app.get('/failurejson', function(req, res) {
res.json({ message: 'hello' });
});

Resources