Session data doesn't seem to be persisting between routes - node.js

I am using a middleware to check if a user is logged in to see certain pages which I've declared in a separate file from the route that I use to login. The middleware adds req.originalUrl to the req.session.returnTo field. I am using passport.authenticate in my login route to serialize a user onto the session but when it does so it takes away the req.returnTo field somehow ? I don't understand why.
middleware I'm using:
module.exports.isLoggedIn = (req, res, next) => {
if(!req.isAuthenticated()){
req.session.returnTo = req.originalUrl;
req.flash('error', 'Must be Signed in first');
res.redirect('/login');
}
else{
next();
}
}
This req.returnTo field does not show up when I try to use it in the login route:-
router.post('/login', passport.authenticate('local', { failureFlash: true, failureRedirect: '/login' }), (req, res) => {
req.flash('success', 'Welcome back !');
const redirectUrl = req.session.returnTo || '/campgrounds';
res.redirect(redirectUrl);
})
redirectUrl value is null

Try by saving session data as bellow
module.exports.isLoggedIn = (req, res, next) => {
if(!req.isAuthenticated()){
req.session.save(function(err) {
// session saved
req.session.returnTo = req.originalUrl;
})
req.flash('error', 'Must be Signed in first');
res.redirect('/login');
}
else{
next();
}
}

Related

express server redirect issues

I'm building/learning a web-app with React and Express. All of the routes and redirects work but URL won't change and my props won't pass until i manually go to the URL.
For example;
After a successful login (local passport with MongoDB), it renders main page but it's empty since i don't get any data (user id or email etc..) but if enter URL manually or press home button on nav-bar, it works or if i logout it logouts but URL stays at /logout instead of /login. Example code below:
server.js
...
server.use((req, res, next) => {
res.locals.success_msg = req.flash("success_msg");
res.locals.error_msg = req.flash("error_msg");
res.locals.error = req.flash("error");
res.locals.messages = req.flash();
res.locals.user = req.user;
next();
});
server.get("/index", ensureAuthenticated, (req, res) => {
const msg = {name: req.user.name, email: req.user.email};
return app.render(req, res, "/index", msg);
});
server.post("/login", (req, res, next) => {
passport.authenticate("local", function(err, user, info) {
if (err) {
return next(err);
} else if (!user) {
req.flash("error_msg", info.message);
return app.render(req, res, "/login", req.flash());
} else {
req.logIn(user, function(err) {
if (err) {
return next(err);
}
req.user = user.name;
return app.render(req, res, "/index", user.name);
});
}
})(req, res, next);
});
server.get("/logout", (req, res) => {
req.logOut();
req.flash("success_msg", "done!");
return app.render(req, res, "/login", req.flash());
});
server.get("*", ensureAuthenticated, (req, res) => {
return handle(req, res);
});
I think that what you meant by return app.render(req, res, "/index", user.name); on your login method, is actually a redirect.
What render does is take the file and the data you give it and then send it back to the browser as a response.
However, what you're trying to do is have the user go to a different URL if the login process is successful, that can be accomplished by doing the following:
res.redirect('/index')
This will make the server go to your index route, which in turn executes all the code required for your user data to be loaded!
You can learn more about redirect and render by looking at the express docs.

Redirecting to previous page after authentication using node.js and passport

my authentication is working well but Redirecting to previous page after authentication using node.js and passport is not working
*//this is auth.route.js file*
app.post('/login', passport.authenticate('login',{
successRedirect : '/',
failureRedirect : '/login',
failureFlash : true
}));
*// this is ensureAuthenticated function*
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
else
res.redirect('/login');
}
I found the how to do it.
*//this is auth.route.js file*
app.post('/login', function(req, res, next){
passport.authenticate('login', function(err, user, info){
// This is the default destination upon successful login.
var redirectUrl = '/profile';
if (!user) { return res.redirect('/'); }
if (req.session.redirectUrl) {
redirectUrl = req.session.redirectUrl;
req.session.redirectUrl = null;
}
req.logIn(user, function(err){
if (err) { return next(err); }
});
res.redirect(redirectUrl);
})(req, res, next);
});
*// this is ensureAuthenticated function*
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
req.session.redirectUrl = req.url;
req.flash("warn", "You must be logged in to do that")
res.redirect('/login');
}

passport-github how to extract session cookie to know that the user already logged in

I am building a passport-github auth to my application. but I think currently I don't know how to extract the cookie from request that would say user is already logged in. so everytime When i go to home page i get redirected to /login.
My code roughly looks like this:
passport.use(new GitHubStrategy({
clientID: authConfig.GITHUB_CLIENT_ID,
clientSecret: authConfig.GITHUB_CLIENT_SECRET,
callbackURL: "http://127.0.0.1:8080/auth/github/callback"
},
function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
return db.user.findOne({where:{github_id:profile.id}})
.then(data=>{
if (data) {
return done(null,data);
} else {
return db.user.build({ github_id: profile.id }).save()
.then(()=>{
return db.user.findOne({where:{github_id:profile.id}})
})
.then(data=>{
return done(null,data);
})
}
});
}
));
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session. Typically,
// this will be as simple as storing the user ID when serializing, and finding
// the user by ID when deserializing
passport.serializeUser(function(user, done) {
console.log("serialize>>>>>", user.github_id);
done(null, user.github_id);
});
passport.deserializeUser(function(id, done) {
console.log("deserialize>>>>", id);
db.user.findOne({where:{github_id: id}})
.then(user=>{
done(null, user.toJSON());
})
});
I have established the session :
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
And I have an isAuthenticated function that checks for req info:
function isAuthenticated (req, res, next) {
// If the user is logged in, continue with the request to the restricted route
console.log("req.user is>>>>", req);
if (req.isAuthenticated()) {
return next();
}
// If the user isnt' logged in, redirect them to the login page
return res.redirect("/index");
}
I am using this passport-github lib. I cannot get some useful information from reqseems
updated to include routes:
Here is the routes:
const isAuthenticated = require('./middleware/isAuthenticated.js');
router
.get('/index', query.renderIndex)
.get('/', isAuthenticated, query.displayRepos)
.post('/', query.queryRepoTopic)
.post('/trending', query.addRepo)
.post('/addTopic', query.addTopic)
.get('trending', query.updateScore);
router.get('/login', auth.loginPage)
.get('/auth/github',
passport.authenticate('github', { scope: [ 'user:email' ] }),
function(req, res){}
)
.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/login' }),
auth.signInRedirect
)
.get('/logout', auth.logout);
Here is the controller function that does the logic:
const loginPage = (req, res) => {
res.render('index');
}
// signin a user in
const signInRedirect = (req, res) => {
console.log("here in callback>>>");
console.log("req.user is>>>>", req.user);
//res.json("you have successfully logged in!");
res.redirect('/');
}
const logout = (req, res) => {
req.logout();
res.redirect('/index');
}
I see you have this route configuration:
const isAuthenticated = require('./middleware/isAuthenticated.js');
router
.get('/index', query.renderIndex)
.get('/', isAuthenticated, query.displayRepos)
...
If you want to call localhost:3000, and be redirected to auth/github when you are not logged in, you could change isAuthenticated function like this:
function isAuthenticated (req, res, next) {
// If the user is logged in, continue with the request to the restricted route
console.log("req.user is>>>>", req);
if (req.isAuthenticated()) {
return next();
}
// If the user isnt' logged in, redirect them to the github login page.
return res.redirect("/auth/github");
}
Wich means, when you try to call the '/', the isAuthenticated will check if the req.user was set (if (req.isAuthenticated())), if not, redirect to the /auth/github route.
Have you tried this?
Have it can help!

Use Passport Local & JWT Strategy on same app (on same route)

so my route (for '/dash') looks like this:
// validating using JWT
router.post('/dash', passport.authenticate('jwt', {session: false}), function (req, res) {
res.json({'success': true});
});
// validating using LOCAL
router.post('/dash', authenticationHelpers.isAuth, function (req, res) {
res.json({'success': true});
});
// authenticationHelpers.isAuth
function isAuth(req, res, next) {
if (req.isAuthenticated())
return next();
res.status(401).json({"authenticated": false});
}
So, how do I use both Local & JWT Strategy on same app (on same route) ? How do I combine them both.
Note: Local for web app, JWT for mobile app
Finally figured it out.
Modified isAuth function:
function isAuth(req, res, next) {
if (req.headers.authorization) {
passport.authenticate('jwt', {session: false}, function (err, user, info) {
if ((!err || !info) && user) {
req.user = user;
return next();
}
res.status(401).json({authenticated: false, message: "Login expired."});
})(req, res, next);
} else {
if (req.isAuthenticated())
return next();
res.status(401).json({authenticated: false});
}
}
Suggestions are welcomed...

Can you authenticate with Passport without redirecting?

I have the following working code to authenticate through the passport-local strategy:
app.post('/api/login', passport.authenticate('local-login', {
successRedirect : '/api/login/success',
failureRedirect : '/api/login/error',
failureFlash : true
}));
app.get('/api/login/error', function(req, res) {
res.send(401, {error: req.flash('loginMessage')});
});
app.get('/api/login/success', function(req, res) {
res.send(200, {user: req.user});
});
However, ideally I want to handle the errors and success messages from one express route, and not redirect to two extra routes.
Is this possible? I tried using a 'custom callback' but that seemed to error out on serializing users for some reason.
You can use custom callback, such as:
passport.authenticate('local', function (err, account) {
req.logIn(account, function() {
res.status(err ? 500 : 200).send(err ? err : account);
});
})(this.req, this.res, this.next);
In err object you can find all needed errors, which was appeared at authentication.
Are you using Mongoose?
Try adding this to your server.js/index.js
var User = mongoose.model('User');
passport.use(new LocalStrategy(User.authenticate()));
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
This to your routes index.js
var auth = require('./auth');
app.post('/api/auth/login', passport.authenticate('local'),auth.login);
auth.js:
var UserModel = require('../models/user');
var User = new UserModel();
exports.login = function(req, res) {
var user = req.user;
req.login(user, function(err) {
//if error: do something
return res.status(200).json(user)
});
};
Add this to model index.js
var passportLocalMongoose = require('passport-local-mongoose');
userSchema.plugin(passportLocalMongoose, {
usernameField: 'email',
usernameLowerCase: 'true'
});
I'm making a lot of assumptions on structure and packages here. but this should work
EDIT
For custom callbacks:
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);
});
Here you instead of res.redirect you can use something like return res.status(404).json("Not Found)
See docs for more information : http://passportjs.org/guide/authenticate/

Resources