express server redirect issues - node.js

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.

Related

Session data doesn't seem to be persisting between routes

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();
}
}

How to take JSON Objects and put them in HTML

I want to put information about user (information from discord, like username and discriminator) in website. When authorized, all data in formal JSON. Here's code.
"/callback",
passport.authenticate("discord", { failureRedirect: "/" }),
function(req, res) {
res.redirect("/dashboard");
} // auth success
);
app.get("/logout", function(req, res) {
req.logout();
res.redirect("/");
});
app.get("/dashboard", checkAuth, function(req, res) {
//console.log(req.user)
res.json(req.user);
});```

Express router ordering for params in beginning of url path

I am using express and I want to have my user profile URLs like this: example.com/:username
However, I still need other URLs such as example.com/login and example.com/view/:id
If I order the router like this, it treats "login" as a username when a request is sent to example.com/login:
router.get('/:username', function (req, res, next) {
res.render('profile', {data: req.params.username});
})
router.get('/login', function (req, res, next) {
res.render('login', {data: null});
})
router.get('/view/:id', function (req, res, next) {
res.render('view', {data: req.params.id});
})
If I put the /:username router at the end, everything works correctly. However, if someone went to example.com/view (without an id), I need it to send an error that the view controller didn't receive an id. Instead, it sees it as a username again and instead sends an error that the username doesn't exist.
What is the cleanest way to solve this? Do I just have to add a router for all base url paths? (Something like this):
router.get('/login', function (req, res, next) {
res.render('login', {data: null});
})
router.get('/view/:id', function (req, res, next) {
res.render('view', {data: req.params.id});
})
router.get('/view', function (req, res, next) {
res.render('viewError', {data: null});
})
router.get('/:username', function (req, res, next) {
res.render('profile', {data: req.params.username});
})
I am not entirely sure if this is the right way to do it, but then again this sounds like something I might encounter and I would like it to be solved by this method until I find a better solution.
The below solution uses a single route for the path format /:value, be it login, view or any username, hence you could put in a simple if-else-if or switch to give control to respective controllers or just simply render a view from it. This way the order in which it has to be handled doesn't matter at all.
router.get("/:username", function(req, res, next) {
if (req.params.username === "login") {
res.render("login", { data: null });
} else if (req.params.username === "view") {
res.render("viewError", { data: null });
} else {
res.render("profile", { data: req.params.username });
}
});
router.get("/view/:id", function(req, res, next) {
res.render("view", { data: req.params.id });
});

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');
}

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...

Resources