ExpressJS: How to conditionally start session? - node.js

This may sound like a really simple/silly question, but I can't find anything about it on the web.
I'm using Express 4 with NodeJS and trying to implement session using express-session middleware. I want to use session to allow/disallow certain routes for different users.
I know I can use session on conditional route:
const express = require('express');
const Router = require('express').Router;
const router = new Router();
const session = require('express-session');
const sessioning = session({...});
router.post('/login', sessioning, (req, res) => {
});
But that's not what I'm trying to do. That will start a session even for failed login attempt.
What I'm trying to do is to start the session only after a successful login attempt:
const express = require('express');
const Router = require('express').Router;
const router = new Router();
const session = require('express-session');
router.post('/login', (req, res) => {
/* ... Login validations */
if (login === 'success'){
/* ... start session */
}
res.json({...});
});
So that I can disallow unauthenticated users from protected routes:
router.get('/protected', (req, res) => {
if (!req.session){
res.status(401);
res.end();
return;
}
/* ... */
});
If I set session directly on protected routes, then it can't verify whether or not a user is logged in.
Can anyone point me to the correct direction?

This does not answer your primary question but address your (seemingly) main concern:
If I set session directly on protected routes, then it can't verify whether or not a user is logged in.
You can attach a variable to the req.session object to check if user is logged in.
Set loggedIn in status in your login route
router.post('/login', (req, res) => {
/* ... Login validations */
if (login === 'success'){
req.session.loggedIn = true;
}
// ...
});
And set up a middleware that checks wether the user is logged in and protect your routes.
function checkLoggedIn(req, res, next) {
if (req.session.loggedIn)
next();
else
res.redirect('/login')
}
// Your protected route
router.get('/protected', checkLoggedIn, (req, res) => {
// ...
});

Related

How to route to a dynamic URL expressJS?

I want to create a login page, such that when the user successfully logs in the app goes to the URL localhost:3000/:username. So for instance when a person with username johnlogs in the app should go to localhost:3000/john. I read this page on express routing https://expressjs.com/en/guide/routing.html but it does not seem to explain this. It only explains how to get the username from the URL but not the other way around (how to route to a different URL depending on the username). Any hints would be appreciated.
You can use redirection after the user login successfully.
var express = require('express');
var app = express();
// login page
app.get('/login', function (req, res) {
res.send(`This is login page`);
});
// login verification
app.post('/login', function (req, res) {
// verify user
const user = getUserByEmailAndPassword(req.body.email, req.body.password);
// set session
// ...
// redirect
res.redirect(`/${user.username}`);
});
// private user page
app.get('/:username', function (req, res) {
const username = req.params.username;
res.send(`Hello ${username}`);
});

How to add authorization in express routes?

Let's say i have several routes in express like,
app.use('/login', login);
app.use('/blogs', blog);
app.use('/news', news);
app.use('/profile', profile);
Here, login, blog, news, profile is routes .js files which contains different get/post routes. I.E. /blogs/new or blogs/:id/edit etc.
Suppose I have 2 users in my system, A and B.
A can access /blogs and /news but can't access /profile
B can access /profile but not the other two.
And /login can be accessed by any user.
How do i do this with express and node?
Is there any way i can set a user to be permitted only to access /profile route and it's children route?
P.S i don't want to use passport.
You can use passport.js for this purpose. Here is an example code for adding passport to your application.
1)Add following lines to packages.json
"passport": "^0.4.0",
"passport-jwt": "^3.0.1",
2). And the following code in server.js. Passport.js has multiple strategies for authentication. Here is configuration for jwt
var passport = require('passport');
app.use(passport.initialize());
require('./server/config/passport')(passport);
var auth = passport.authenticate('jwt', { session: false });
app.use('/your/path/*', auth, function (req, res, next) {
next();
});
Passport with check all the paths like /your/path/* ( i hope you know that).
I will demonstrate this with the cookie session. first lets set up a session. i will be using mongod, for different databases, express-session has different packages to save the session.
//------ app.js----------
const session = require("express-session");
const MongoDbStore = require("connect-mongodb-session")(session);
const store = new MongoDbStore({
uri: "mongodb://localhost:27017/yilmaz",
collection: "sessions",
});
// ------ this adds "session" property to the req
app.use(
session({
secret: "anyhting long",
resave: false,
saveUninitialized: false,
store: store,
})
);
First step of authentication is signing up. We save user's email and password. Next step user logs in the system. In this step we check if the email (or username) and password are in match.
exports.postLogin = async (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
const user = await User.findOne({ email });
if (!user) {
return res.redirect("/login");
}
const match = await bcrypt.compare(password, user.password);
if (match) {
// when we protect the routes we look at this property
// session property is attached by the express-session
// -------THIS IS WHERE WE SAVE THE SESSION TO DATABASE
req.session.isLoggedIn = true;
req.session.user = user;
// after req.session.user is set, everytime client makes a request, our middleware will be checking this
return req.session.save((err) => {
console.log("error in postLogin", err);
return res.redirect("/");
});
}
res.redirect("/login");
};
with checking `req.session.isLoggedin` you can write a middleware and used on the routes.
module.exports = (req, res, next) => {
if (!req.session.isLoggedin) {
return res.redirect("/login");
}
next();
};
in any route you want u can add this middleware
const isAuth = require("../middleware/is-auth");
router.get("/edit-product/:productId", isAuth, adminController.getEditProduct);

Special Passport Authentication for Specific Route

I'm developing a RESTful API with Express.js and I'm using Passport.js for authentication purposes.
Here is an example of how I'm using passport with routes:
const beerRoutes = require('./beerRoutes') // an instance of express router
let authenticateRoute = passport.authenticate('jwt', { session: false })
router.use('/beer', authenticateRoute, beerRoutes)
Inside beerRoutes.js :
const router = require('express').Router()
router.post('/', (req, res) => {})
router.get('/', (req, res) => {})
router.patch('/', (req, res) => {})
router.delete('/', (req, res) => {})
The problem is, I want unauthenticated clients to be able to create new users (i.e. POST /beer/).
But I also want to give additional permissions to authenticated clients when they send a request to the same endpoint.
How can I achieve this without letting unauthenticated clients to access other routes inside beerRoutes (e.g. PATCH /beer/)?
This can be addressed with a custom middleware which calls the Passport.js middleware.
const authenticationWhiteList = [
'POST /beer'
]
function Authenticate (request, response, next) {
let route = `${request.method} ${request.baseUrl}`
if (_.indexOf(authenticationWhiteList, route) !== -1) {
next()
} else {
passport.authenticate('jwt', { session: false })(request, response, next)
}
}
Then change the authentication code to this one:
const beerRoutes = require('./beerRoutes') // an instance of express router
// let authenticateRoute = passport.authenticate('jwt', { session: false })
let authenticateRoute = Authenticate
router.use('/beer', authenticateRoute, beerRoutes)

Passport req.logOut() function not working? [duplicate]

This question already has answers here:
Why is PassportJS in Node not removing session on logout
(28 answers)
Closed 4 years ago.
I am trying to incorporate the Passport logout function into one of my get-request routes for express and it doesn't seem to be destroying the session. After I make a logout request the endpoint that I am trying to hide is still accessible.
Here is the code:
const express = require('express');
const router = express.Router();
const app = express();
const path = require('path');
const passport = require('passport');
const passportHttp = require('passport-http');
const logout = require('express-passport-logout');
router.get('/', function (req, res) {
logout();
console.log('logged out');
res.sendFile(path.resolve('./public/logout.html'));
})
module.exports = router;
Any help would be appreciated! Thanks!
Have you tried using req.logout(); instead of logout();
without these 2 packages?
const passportHttp = require('passport-http');
const logout = require('express-passport-logout');
The given module actually returns a router handler i.e. function (req, res) {..}. Which in your case does not take req. You can see the source code here.
You can use it like this:
router.get('/logout', logout());
You can use a module like following as middleware:
var logout = function() {
return function (req, res, next) {
req.logout();
delete req.session;
next();
};
};
router.get('/', logout, function (req, res) {
console.log('logged out');
res.sendFile(path.resolve('./public/logout.html'));
})
If you are using express locals, then after req.logout(), add this line:
req.user=null
or
delete req.user
I hope this helps
/* Handle Logout */
router.get('/logout', function(req, res) {
console.log("I am Logout")
req.logout();
res.json({
status: "logout",
msg:"Please Log In again"
});
});
This will work for sure as far as you don't have any mistake at frontend.

Express.js ERR_TOO_MANY_REDIRECTS error

Here's the scenario.
If a user wants to see a page that requires user access, I want to redirect him to the homepage, but I get ERR_TOO_MANY_REDIRECTS error when I try to access the homepage.
I couldn't figure it out how to solve this.
app.js
exports.ensureAuthenticated = function (req, res, next) {
jwt.verify(req.cookies.userToken, "NICETRY", function (err, decoded) {
if (err) {
res.redirect("http://localhost:4000");
} else {
// no err
if (decoded.id) {
req.id = decoded.id;
req.iat = decoded.iat;
next();
} else {
res.send("invalid cookie");
}
}
});
};
routes/frontend/index.js
var express = require('express');
var router = express.Router();
var indexController = require('../../controllers/frontend/indexController');
var auth = require('../../app').ensureAuthenticated;
router.get('/', auth, indexController.index);
module.exports = router;
indexController.js
exports.index = function (req, res) {
res.render('frontend/home/index');
};
The issue is that you're redirecting back to the same page once authentication fails and so your ensureAuthenticated middleware runs again and redirects again.
Try making one authenticated route and one unauthenticated route.
router.get('/', indexController.index); // no auth necessary
router.get('/private', auth, indexController.private); // requires auth
Now if you fail auth when you visit /private it will redirect to / which will display to the unauthenticated user.

Resources