toutpt
toutpt

Reputation: 5220

How to protect static folder in express with passport

I have a project based on express with a required authentication based on passport.

The backoffice is an angularjs app served as static files.

My authentication code is completly based on https://github.com/jaredhanson/passport-local/blob/master/examples/express3-no-connect-flash/app.js

To do not serve the angular app if you are not authenticated. I have try by adding ensureAuthenticated on the /admin route but it make the route not working (404). Once I remove ensureAuthenticated the /admin is served.

app.use(express.static(path.join(__dirname, 'public')));
app.use('/admin', ensureAuthenticated, express.static(path.join(__dirname, 'admin')));
//serve routes
app.use(app.router);

The public folder contains the login page.

How could I achieve this ?

Upvotes: 37

Views: 42558

Answers (6)

ahoys
ahoys

Reputation: 31

The accepted answer felt a bit partial (and may not work in some cases), so here's a bit more verbose and generalized answer:

// Here we'll attach the user object. The correct ordering 
// of these middleware functions is important.
app.use(
  '/some-restricted-static-path',
  passport.authenticate("bearer", { session: false })
);

// As the user object should now be attached (if authorized), we can now
// verify it to be so.
app.use('/some-restricted-static-path', (req, res, next) => {
  if (!!req.user) {
    // The user exists, we can continue.
    // Here you can also validate the role etc if necessary.
    next();
  } else {
    // No user object found, terminate the pipeline with .end().
    res.status(401).end();
  }
});

// And finally, here's the actual handler that won't be accessed if 
// something went wrong earlier.
app.use(
  '/some-restricted-static-path',
  express.static(
    path.join(
      __dirname,
      "../dist/attachments"
    )
  )
);

Explanation: In Express, the middleware is processed one-by-one. If one of the middleware terminate the process, every middleware after it will be skipped. So, knowing this, we can first attach the user object, then validate it, and finally either grant or deny access.

Upvotes: 3

Mahan Zendedel
Mahan Zendedel

Reputation: 86

You could also chain middlewares as an array to achieve this goal:

app.use('/admin', [ensureAuthenticated, express.static(path.join(__dirname, 'admin'))]);

Upvotes: 3

l2ysho
l2ysho

Reputation: 3063

Update for [email protected]+, [email protected], and [email protected]

First setup a passport auth strategy. If you use a jwt, you can take a token from a query parameter, if not you can use another Extract function (or multiple using Jwt.ExtractJwt.fromExtractors())

passport.use('basic-user',
    new Jwt.Strategy({
        ...jwtConfig.options,
        jwtFromRequest: Jwt.ExtractJwt.fromUrlQueryParameter('token')
    }, verifyUser)
);

Then you can use a passport authenticate function before serving static files

app.use('/files', [
    passport.authenticate(['basic-user'], { session: false }),
    express.static(path.join(__dirname, 'files')) //make sure you access proper directory
])

Upvotes: 4

Bobz
Bobz

Reputation: 2604

Ran into same issue, this is what I ended up doing!

app.use doesn't let you chain middlewares in that way. The various app.VERB functions do, but app.use doesn't. That's for one middleware at a time.

If you split the 2 middlewares out into separate calls, you should get the results you want:

app.use('/admin', ensureAuthenticated);
app.use('/admin', express.static(path.join(__dirname, 'admin')));

Cannot use basic authentication while serving static files using express

Upvotes: 40

vodolaz095
vodolaz095

Reputation: 6986

app.use('/admin', function(req,res,next){
 if(req.user){
   return express.static(path.join(__dirname, 'public'));
 } else {
   res.render(403, 'login', {message:'Please, login!'});
 }
});

//serve routes
app.use(app.router);

Upvotes: 14

MikeSmithDev
MikeSmithDev

Reputation: 15797

You can check the route using middleware and redirect them if they aren't logged in and are hitting admin pages, something like (untested):

app.use(function(req, res, next) {
    if (req.user == null && req.path.indexOf('/admin') === 0)
    {
        res.redirect('/login');
    }
    next(); 
});

Upvotes: 27

Related Questions