Server authentication on page request in nodeJS, angularJS Application - javascript

I am using passport.js for authentication. My requirement is that, anyone should not be able to access a particular page (say, '/restricted'), if one is not logged in.
Right now, in my application, anyone can access "localhost:3000/#/restricted" url directly.
I am able to stop this and allow only logged in users to access the page by using Rorschach120's solution in
Redirect on all routes to login if not authenticated.
But this is done client side and is not that secure, because anyone can access this code from browser.
So I need that the request for my page goes to server, I tried moka's solution in How to know if user is logged in with passport.js?:
In app.js:
app.get('/restricted', loggedIn, function(req, res, next) {
// req.user - will exist
// load user orders and render them
});
where the loggedIn() function checks if user is logged in or not.
But this middleware is NEVER called and anyone can still access the "restricted" page.
What can I do, so that this gets called?
I am new to AngularJS and NodeJS. Am I doing something wrong here?
Any help will be appreciated.

You can use middleware for that purpose.
app.get('/secure-route', secureMiddleware, myMethod)
let secureMiddleware = function(req, res, next) {
authCheck(...)
.then(function(result) {
// pass
next()
})
.catch(function(err) {
res.status(401).json({
code: 401,
message: 'restricted route'
})
})
}

Related

Error when calling the next() method in passport.authenticate('local')

I have some middleware which uses passport.js, which aims to authenticate a user, then move onto the next piece of middleware:
exports.authenticate = (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
console.log('You are authenticated!!')
next()
})(req, res, next)
}
When the user registers, I see You are authenticated!! in my console. So by this logic, the user should be attached to the req. So I call next and it moves onto this piece of middleware (I want to do something else before the user is redirected):
exports.createMatch = async (req, res) => {
console.log(req.user._id)
}
However, an error on my console and webpage shows TypeError: Cannot read property '_id' of undefined. Why is this and how do I rectify it?
routes.js:
router.post(
'/register',
userController.validateRegistration, // validate them
userController.register, // register them to the db
authController.authenticate, // authenticate them
catchErrors(dataController.createMatch) // do some other bits then redirect
)
Fairly new to Express. If more code is needed let me know. Apologies if something similar was answered elsewhere.
Regards,
James.
This is the line in the source where req.user gets set:
https://github.com/jaredhanson/passport/blob/821a474342b1ae900849911b5c3d3ccc4ef5ab86/lib/http/request.js#L44
It's in the method req.login. The documentation is here:
http://www.passportjs.org/docs/login
It states:
When the login operation completes, user will be assigned to req.user.
Further it says:
passport.authenticate() middleware invokes req.login() automatically.
So far everything sounds like it should work...
However, if you read the section about providing a Custom Callback, which is what you're doing, it states:
Note that when using a custom callback, it becomes the application's responsibility to establish a session (by calling req.login()) and send a response.
There are several ways to fix it. You could get rid of the custom callback, you could call login inside the callback, or you could just set req.user = user yourself.

Making a proper error page in node.js

My webpage requires that people log in to access the website. Some pages can only be viewed when a user logs in. For example, here is a route to a profile page that can only be viewed once logged in (express):
router.get('/profile', function (req, res) {
User.findOne({_id: req.user._id}, function (err, user) {
if (err) {
return next(err)
} else {
res.render('main/profile', {user: user});
}
});
});
If someone tries to access the /profile page without logging in, they will get a page with a bunch of errors on it.
What I want to be able to do is, instead of showing a page of random errors, direct these types of users to a proper error page. I've tried replacing return next(err) with something like res.json(You cannot access this page'), but that doesn't seem to be working.
This is the answer to my question, using the link in the comment section above. Basically, when someone tries to access parts of my website without logging in, they will be re-directed to an error page located in the folder errors and the filename 500. And because this specific type of error is a 500 code error, we used res.status(500). here is the complete code (which goes in the main server file):
app.use(function(err, req, res, next) {
res.status(500);
res.render('errors/500');
});

How can I access User Info with AngularJS after NodeJS verification?

I've seen a few questions regarding this but being new to both Angular and Node I'm struggling to find a proper solution.
I had this code, which worked for the login and I could only access my pages after being authenticated:
router.post('/login',
passport.authenticate('local',
{
successRedirect: '/',
failureRedirect: '/login',
failureFlash: false,
successFlash: false
}
));
router.all('*', ensureAuthenticated);
function ensureAuthenticated(req, res, next) {
console.log("in ensureAuth", req.isAuthenticated());
console.log("session data", req.session);
console.log("user data", req.user);
if (req.isAuthenticated())
{
return next();
}
res.redirect('/login');
}
The local passport authentication I have returns an object after verifying if the user exists and allows login, as such:
return passportDone(null, result.rows[0]);
with result.rows[0] being the user info I want.
What I had in the front end is a simple ng-submit in the form that calls the "login(credentials)" with credentials being set by ng-model in their respective fields (username and password).
My question is how can I return all the info I want, such as user_role, name and stuff, so I can present it in the front-end as {{user.name}} for example?
The info needs to stay after refreshes so $scope isn't an option from what I've read.
What you probably want to do here, is create a custom route for fetching this information. for example: "/me".
In this route, you can serve the information you now probably store in your session variable.
Another solution, depending on how your application works with authentication, is to inject the userinfo (For example if you log in, and get redirected to a new page, you can inject the userinfo into the new page as a js variable) or to return the userinfo in the response if you send a ajax request to login and dont get redirected to a new page by the server.
I hope you are using passport.js local authentication.I would recommend to store user infomation after authentication in cookies as a json webtoken or using some other encryption.And you should expose an api(/api/is-authenticated) which is used to check whether the user is authenticated, by sending the token stored in cookies.when ever you refresh or navigate to other routes make an api(/api/is-authenticated) call to check whether that particular user has already authenticated or not.
Ok, I got it.
I already had the service and all but the problem was with passport's successfulRedirect. It returns the html you want when it succeeds, which is fine. However, since I wanted the user info, it wasn't enough. What I did was create an /account route that returns the req.user info, which I then handle in the front end and form a cookie with it. What basically happens is:
post_login->verify_user->success->get_account->form_cookie->render_html

PassportJS - Dynamically set state to allow redirect on callback

So I'm working off the information that was given here to add the ability that Google will redirect to the page a user was at before it redirected to google. I'm currently using the latest versions of Express, PassportJS, and Google oauth2.
For example, if a user hits page http://example.com/privatecontent, it'll automaticially redirect to Google asking to sign in, and after it's sucessful it returns to my Node App, except it doesn't know the last page was /privatecontent and instead redirects to the index.
If I understand right, I can use the state parameter to let Google know to send the state param back so I can read it and redirect myself.
I essentially would like my function to look a little something like this, but I don't have access to req.headers, or just don't know how honestly within passport.authenticate.
app.get("/auth/google", passport.authenticate("google", {
scope: ["https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"],
state: base64url(JSON.stringify({
lastUrl: req.headers['referer']
}))
}), function(req, res) {});
Make a custom middleware
function myCustomGoogleAuthenticator(req, res, next){
passport.authenticate({
scope: ...
state: // now you have `req`
})(req, res, next);
//^ call the middleware returned by passport.authenticate
}
Add that to your route instead
app.get("/auth/google", myCustomGoogleAuthenticator, function(req, res) {});

Unexpected behavior when validating a session token using parse.com

I'm trying to build a simple application with parse.com as my user manager.
I would like to make a login call to parse.com from my client side, and call my node.js server with the user's session token (I'll add it as a cookie). In the server side, I'll validate the session (using https://parse.com/docs/rest#users-validating) and allow access only if the session is valid.
For example (in my server):
app.get('/api', function(req, res, next) {
var token = getTokenFromRequest(req);
if(tokenIsValid(token)) {
next();
} else { // Redirect... }
});
app.get('/api/doSomething', function(req, res) {
// Do something....
});
the tokenIsValid(token) function should be implemented using https://parse.com/docs/rest#users-validating.
However, it seems that the REST API user validation returns the user even if the user is logged out (expected to return 'invalid session').
Is this a bug in the REST API user validation? What am I doing wrong? Is there a better way for doing that?
Thanks!
Via REST there's no concept of sessions really. REST calls are meant to be stateless meaning that the (current) user at /me will be serialized from the token provided. If the token is associated to a user it will return the JSON representation of that user otherwise in returns an error.
One way or another that call is asynchronous so you can't really use it in and if statement.
You can do:
app.get('/api', function(req, res, next) {
var token = getTokenFromRequest(req);
serializeUserFromToken(token,function(err,parseResponse) {
if(err) return next(err)
if(parseResponse.code && parseResponse.code === 101){
// called to parse succedded but the token is not valid
return next(parseResponse);
}
// parseResponse is the current User.
next();
});
});
Where serializeUserFromToken makes a request to Parse with the token in the X-Parse-Session-Token header field.

Categories