Nodejs express res.redirect loop - node.js

Using Nodejs and an Express server I'm trying to prevent anyone from reaching my second set of routes without logging in and while this works I get stuck in a redirect loop if the session doesn't detect the email in the session token. I believe its trying to check for the req.session.email for the /users endpoint as well causing the redirect loop but as the session checking middleware is used after I thought the /users endpoints would avoid the check.
How can I organize my code so that the books endpoints can only be reached when the req.session.email is satisfied and also not get stuck in a redirect loop when someone tries to reach it without being logged in?
app.use('/users', users)
app.use((req, res, next) => {
if(!req.session.email){
res.redirect('/login')
}
else{
next();
}
})
app.use('/books', books);

The order of the app.use statements is not really important in this case; You could add your middleware to the route-level if you're only checking the /books endpoint.
const yourMiddlewareFunction = (req, res, next) => {
if(!req.session.email){
res.redirect('/login')
}
else{
next();
}
}
app.use('/books', yourMiddlewareFunction, books);

If you only want to protect the /books endpoints, you can do it like this :
function requireLogin(req, res, next) {
if(!req.session.email){
res.redirect('/login')
}
else{
next();
}
}
app.use('/books', requireLogin, books);

Related

Express middleware `router.use` vs function

router.use((req, res, next) => { // export as single route in a file
if (req.isAuthenticated()) {
next();
return;
}
res.sendStatus(401);
});
const authenticate = (req, res, next) => {
if (req.isAuthenticated()) {
next();
return;
}
res.sendStatus(401);
};
The above are 2 ways of writing the authentication route for use in another route (like below). Which way is preferred and why?
router.post('/', authenticate, (req, res, next) => {});
The above way will affect all the requests that your ExpressJS app is
serving, where as the second approach uses Object oriented scripting
way to authenticate only those requests that require authentication.
Say your are writing a sign in or sign up API, you wouldn't need an authentication parameter for that unless mentioned otherwise.
****UPDATE****
The first approach will affect all the requests that your router is serving.
You probably have used the router in your App.js file as
const myRoute = require('./routes/test'); // where `test.js` is a file in routes folder with your code above
app.use('/some_route', myRoute);
All requests going to http://servername:port/some_route/.... will be filtered in your test.js file now.

skip token verification for GET request

I want skip token verification for GET method in express. I want to allow GET request for everyone while just post, put, delete request by authorized user.below is my logic but the response hanging. I tried to used nested express use method.
app.use(function(req, res, next) {
if (req.method === 'GET') {
app.use('/api/someroute', routes);
}
else{
//do verification below the next
next();
}
})
or is there any other way to handle this
Just include a middleware on desired routes :
var router = express.Router();
// no middleware included for get request
router.get("/route1", handlerRoute1);
router.get("/route2", handlerRoute2);
// include some middleware
router.post("/route3", myMiddleware1, myMiddleware2, handlerRoute3);
app.use(router);
Where myMiddleware1 and myMiddleware2 looks like :
myMiddleware1 = function(req, res, next){
// verify token, etc, ....
var success = true;
// call next on success
if(success)
return next();
else
{
// raise error
return res.status(500).json({error: "Missing token..."});
}
};
It's because in the scenario for GET requests you don't actually complete the request (or move on from that middleware). Middleware is processed in sequential order i.e. first come first served. If you only want to protect everything other than GET requests then something like this would be fine:
app.use(function(req, res, next) {
// let GET requests through
if (req.method === 'GET') return next();
// perform token auth on all other requests, next() if OK
});
// setup routes
app.use('/api/someroute', routes);
You would setup your middleware first then declare your routes after, this means any requests coming in will have to pass through your token check, in this case you just skip GET requests.

Using Passport to authenticate based on dynamic route

I'm building an API with Node.js, and I have some endpoints I want to secure.
For simplicity let's assume I'm using HTTP basic authentication (passport-http) for all of my endpoints.
What I'd like to do on top of that, is to make sure that a route like this: api.example.com/users/:uid/ is only accessible by a user with that ID.
I can do it with something like this:
app.get('/users/:uid',
passport.authenticate('basic', {
session: false
}),
function (req, res, next) {
if (req.params.uid !== user.id) {
return next(new Error('Unauthorized'));
}
return next();
},
function (req, res, next) {
// do secret stuff
}
);
But I wonder if there's a way to do this without adding additional middleware, by using Passport itself:
app.get('/users/:uid',
passport.authenticate( ??? ),
function (req, res, next) {
// do secret stuff
}
);
Is it possible? If not, is there a better way?
You can try something perhaps like this. General description: authenticate all requests that hit anything under the /users route as requiring authentication. On your specific route, use some middleware that makes sure that the user trying to access the specific route is the one in the route itself via that uid.
function authorizeUser(req, res, next) {
if (req.user.uid !== req.params.uid) next(new Error('Not your profile!'));
next();
}
// Require login for entire /users section
app.use('/users', passport.authenticate('basic', { session: false }));
// Authorize /users/:uid section to one user
app.use('/users/:uid', authorizeUser);
// Nested routes will all be secured by the middleware above.
app.get('/users/:uid', function (req, res) {
// Secret stuff
});
app.get('/users/:uid/foo/bar', function (req, res) {
// Also secret
});
If you're only securing one endpoint, you can just put it all on the same route.

Using Express 4 how to redirect to my own route without losing req and response data?

I have my application structured with 3 Routes (api, admin, default). Each lives in there own file and has it's own middleware and exports a Route. The problem I am facing is when I want to forward to another route that lives on a different router. Essentially I want to call the same function so that I am not serving up the same view from multiple locations.
I don't want to user res.redirect('/someplace') because I want to be able to pass the req and res objects on to the method.
|-app.js
|-routes
|---admin.js
|---api.js
|---default.js
The routes are required and used in app.js as follows
app.use('/api', require('./routes/api')(passport);
app.use('/admin', require('./routes/admin')(passport);
app.use('/', require('./routes/default')(passport);
Inside of admin if have a situation where I need redirect to login and pass some data
// authenticates all routes for the admin router
router.use(function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.flashMessage.push('Session expired'); //is lost after redirect
res.redirect('/login');
//do I need to restructure my whole app so that I don't
//have to call res.redirect('login')
});
Any ideas on how to structure this? Do I need to export every method and keep all of my routes in one router file? That doesn't very clean, but if the functions are somewhere else it may be too messy.
You can forward it by calling the next callback ,but only if you do not use any paths.
app.use(function(req, res, next) {
// ... api
next();
});
app.use(function(req, res, next) {
// ... admin
next();
});
Another option is use * that will match all paths:
app.use("*", function(req, res, next) {
var path = req.path; // just example how it can be done
if (path === "/api") {
// ...
path = "/admin";
}
if (path === "/admin") {
// ...
}
});
Edit:
I don't think that express has something like next('/login'); ,so basically function that can forward a request to another path and I don't think that is right to have something like this. If a client ask for /admin you should send this particular page and not the page that is under /login. If you want to send back to a client the login page than just redirect it as you did it in your question. I understand that you want to keep the req, res ,but then is the problem in the proposal/structure of your webapp.

Issue with Express and middleware

function redit (req, res, next) {
var session = req.session.user;
if (session) {
res.redirect('/home');
next();
}
else {
res.redirect('/');
next();
}
}
app.get('/', redit, function (req, res){
res.render('home0.ejs');
});
I code this middleware to check if there's a req.session.user, if there is, the user would be redirected to home, if not, would be redirected to /. But when this middleware is called, Chrome says to me Error 310 (net::ERR_TOO_MANY_REDIRECTS)', any solutions...?
You miss the fact that after redirect an anonymous user (with falsy req.session.user value) will end up at the same (/) page - so their identity will be checked up by redir middleware again... and again... and again. Hence the 'TOO MANY REDIRECTS' error.
The common solution is to redirect all the anonymouses to some other gateway page - and that page obviously should NOT check session.user.

Resources