check if current user is logged In - node.js

I have a profile section in my angular app and right now i have 5 users let's say.
I have a route where users have to change the password. I want to verify if users are correctly logged in and has passed authentication and they cannot change password for any other users.
router.get('/change-password/:username', (req, res) => {
User.findOne({
username: req.params.username
}).then(user => {
if (user) {
res.status(200).json(user);
} else if (!user) {
res.status(404).json({
message: 'user not found'
});
}
});
});
what if user A is logged in and he change the parameter to B and then change the password ? is there any way I dont pass parameter and get current user who is logged In

Basically is like this, when you log the user in from back end, you send a response with a token to the front end. You save this token to the local storage to have it in every request to the back end. Them, you use a middleware function to check if the token is provided in the header of the request like a bearer. So the answer is: you don't have to check the auth every request, you just check if the token is provided by middleware and if it is correct.
If you are using express, the most apps use a middleware in the auth service class like this:
module.exports.isAuthorized = function(req, res, next) {
User.findById(req.session.userId).exec(function (error, user) {
if (error) {
return next(error);
} else {
if (user === null) {
var err = new Error('Not authorized! Go back!');
err.status = 400;
return next(err);
} else {
return next();
}
}
});
}
At the node.js routes:
var auth = require('./auth');
// GET route after registering
router.get('/clientPage', auth.isAuthorized, function (req, res, next) {console.log("1114");
res.sendFile(path.join(__dirname + '/../views/clientPage.html'));
});
As you can see, the second param says that before make the request, it will execute the middleware function auth.isAuthorized.

Related

User sessions data does not persist when calling from a different route

My user session does not persist within the server. I can see within the log that I saved it in my /login route, but when I try to access it from a different route, its "undefined".
My /login route:
app.route("/login")
.post(async (req, res) => {
var username = req.body.username,
password = req.body.password;
console.log('\t we are here')
try {
var user = await User.findOne({ username: username }).exec();
if(!user) {
res.redirect("/login");
}
user.comparePassword(password, (error, match) => {
if(!match) {
console.log('Password Mismatch');
console.log('Ensure redirect to /login');
res.redirect("/login");
}
});
req.session.user = user;
console.log('\t\treq.session:');
console.log(req.session)
var redir = { redirect: "/dashboard" };
return res.json(redir);
} catch (error) {
console.log(error)
}
});
In the above snippet I try to save the session data by req.session.user = user;. Its log appears as:
But now when I try to call the session I just stored, it shows "undefined". This is my /dashboard route & its corresponding log:
app.get("/dashboard", (req, res) => {
console.log(req.session.user_sid);
// console.log(req.cookies.user_sid);
if (req.session.user && req.cookies.user_sid) {
// res.sendFile(__dirname + "/public/dashboard.html");
console.log(req.session);
res.send("send something")
} else {
res.send("go back to /login");
}
});
To my understanding, user authentication is done my checking sessions and cookies, which is why I'm trying to save the session to request.session. I want to the data to persist so that I can use it in all my other routes such as when calling /dashboard api.
Dashboard api will be call by a protected route like when the user is logged in.

How does app.get() work on the server file?

I am trying to understand how app.get() works in calling functions when trying to switch between web pages.
I've created a user-login page that assigns a token to the user and checks it in a function.
I use app.post('/login', login); to call the login function which sends the user object to the server. After creating the token I'm hoping to then render the next page in a function after checking the token. (See code below)
However, I don't really understand how app.get('/', checkToken, getProfilePage) is then called. As I don't think it ever gets called.
I've looked at some websites that explain about HTTP requests but I'm struggling to find out, how it all links together inside app.js.
App.js:
app.post('/login', login);
app.get('/', authorize.checkToken, getProfilePage);
function login(req, res, next) {
userService.login(req.body, (err, user) => {
if (err) {
res.redirect('error.ejs');
console.log(error.message);
}
console.log(user);
if (!user) {
res.status(400).json({ success: false, message: 'Username or
password is incorrect' });
}
else {
res.json(user);
}
})
}
The next login function assigns the token and is used above as middleware:
function login({ username, password }, callback) {
grabUsers((err, users) => {
let user = users.find(u => u.username === username && u.password
=== password);
if (user) {
const token = jwt.sign({ username: username }, config.secret,
{ expiresIn: '24h'
}
);
const { password, ...userWithoutPassword } = user;
user = {
...userWithoutPassword,
success: true,
message: 'Authentication successful!',
token: token
}
};
callback(null,user);
})
}
Inside authorize.js:
let jwt = require('jsonwebtoken');
const config = require('./config.js');
let checkToken = (req, res, next) => {
console.log("check token running...");
let token = req.headers['x-access-token'] ||
req.headers['authorization']; // Express headers are auto
converted to lowercase
if (token.startsWith('Bearer ')) {
// Remove Bearer from string
token = token.slice(7, token.length);
}
if (token) {
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.json({
success: false,
message: 'Token is not valid'
});
} else {
req.decoded = decoded;
next();
}
});
} else {
return res.json({
success: false,
message: 'Auth token is not supplied'
});
}
};
module.exports = {
checkToken: checkToken }
getProfilePage function:
module.exports = {
getProfilePage: (req, res) => {
res.render('profile.ejs');
}
}
So my login form posts to /login and then once it has been verified I would like to check the token and then call getProfilePage. But how do I call the app.get() after the login data has been posted and authenticated?
You don't call a route from your app, what you need to do is redirect to it : res.redirect('/');
I believe there is a problem with how you try to authenticate a user. Seems to me you send a token in authorization header which is a common practice when you accessing API. Not sure how/when you generate the token and set this header though...
Anyway, this approach is good for authorization but not so good for authentication.
After successful /login request you should set the authentication cookie (user session). To simplify, you can just generate a JWT with userId encoded into it and use it as the value for this cookie (let's call it user-session).
Now after that each time user makes a request the cookie will be sent with it and you can decode the userId from this JWT. (Same thing, but now you'll take token from req.cookies['user-session'] instead of req.headers['authorization']).
But how do I call the app.get() after the login data has been posted and authenticated?
You can either navigate to this page from the client right after you receive successful /login response if you're using AJAX (i.e. window.location.replace('/')) or you can do res.redirect('/') instead of res.json(user) on successful login if you submit the HTML form without AJAX.
Redirect forces a browser to immediately make another request to the URL you specify and by that time you'll have user-session cookie set, i.e. you'll be able to retrieve userId and return correct profile page.

Email verification using nodejs

Whenever a user registers i am sending him an email which contains the link which user needs to click to get verified. I am passing a token in that link. When the user clicks the link he should get verified but i am not able to do this. I can just retrieve the token from the link but i am unable to find the user in the database and update the value.
Here is my code:
router.route('/verify')
.get(isNotAuthenticated, function(req, res){
var verifyToken = req.query.id;
var user = User.findOne({ 'secretToken': verifyToken });
if (!user) {
req.flash('error', 'No user found with this email id, please check your email id or incorrect link');
res.redirect('/users/register');
return;
}
user.active = true;
user.secretToken = '';
user.save();
req.flash('success', 'Thank you! Now you may login.');
res.redirect('/users/login');
res.redirect('login');
Try using promise to do this instead of assignment.
User.findOne({ 'secretToken': verifyToken })
.then(user => {
// do something with user
})
.catch(err => {
// do something with error
})
If you are using JWT to validate your routes you can:
1 - Generate the link verification with one "hash value"(token), save this token in the user document (user collection).
send the link e.g. "https://site/user/verify?token=3f0621f7e4c41ece51926a40cee4dae0be65ct7"
2 - Disable the security for this route:
app.use(jwt({secret: process.env.SECRET}).unless({path: ['/users/verify']}));
3 - Receive the request to verify the user:
router.put('/verify', bodyParser.json(), function (req, res, next) {
try {
const user = userController.verify(req.query.token);
res.status(200).json(user);
} catch (err) {
next(err);
}
});
4 - Find and update the user(as verified):
User.findOneAndUpdate(
{
token: token,
},{$set:{verified:true}})
.then((result) => {
return result;
}).catch((err) => {
//throw error
});
If you need to wait the update for execute other sttufs, you can use async/wait: Async/Await Tutorial

Express Middleware jsonwebtoken authentication

My server has a registration api that provides a token after registration, and a middleware that authenticates a user's token. I need to register an account to get the token to do something else with my server. However, the middleware blocks my network request because I don't have a token yet.
So how can I create my account and token in this case? Get pass the middleware with some tricks?
Middleware:
// Middleware to verify token, it will be called everytime a request is sent to API
api.use((req, res, next)=> {
var token = req.headers.token
if (token) {
jwt.verify(token, secret, (err, decoded)=> {
if (err) {
res.status(403).send({ success: false, message: "Failed to authenticate user." })
} else {
req.decoded = decoded
next()
}
})
} else {
res.status(403).send({ success: false, message: "No Token Provided." })
}
})
Signin:
// Sign In with email API
api.post('/signInWithEmail', (req, res)=> {
User.findOne({
email: req.body.email
}).select(userFields).exec((err, user)=> {
if(err) {
throw err
}
if (!user) {
res.send({ message: "User doesn't exist"});
} else if (user) {
var validPassword = user.comparePassword(req.body.password);
if (!validPassword) {
res.send({ message: "Invalid Password"});
} else {
var token = createToken(user);
res.json({
success: true,
message: "Login Successfully!",
token: token
})
}
}
})
})
Make a function to check tokens and expose your routes such that whenever you need to call an authenticated route then you'll be checking the token first and then you'll expose the route.
Sample Code
Let's say this is my check token function
function checkToken(req, res, next) {
var x = req.token; //This is just an example, please send token via header
if (x === token)
{
next();
}
else
{
res.redirect(/unauthorized); //here do whatever you want to do
}
}
Now let's use the function for routes.
app.post('/protectedroute', checkToken, routename.functionname);
app.post('/notprotected', routename.functionname);
It's your call if you'd like to have separate routes for different codes or else you can just call specific code block via keeping them in function etc. on the main file i.e. app.js or server.js, whatever you have chosen.
What actually we are doing here is - we are making a middleware of our own to expose our routes through a channel of code blocks or functions.

Restricting Login Access - Passport.js, Google Authentication

Okay, so using passport.js works, and works well, from what I've seen. However, I'm not sure how to properly exclude certain users. If the application is intended to have restricted access, rather than just providing the user a method for logging in, how can I restrict the login through passport.js? As it stands, users can just visit /login and log in with their Google account, thereby getting access to the internals.
Here is one way to do this, with comments throughout. The main thing is understanding this page from the author: http://passportjs.org/guide/authenticate/, which I explain a little more in this example ...
It might be easier to read bottom to top:
var authenticate = function(req, success, failure) {
// Use the Google strategy with passport.js, but with a custom callback.
// passport.authenticate returns Connect middleware that we will use below.
//
// For reference: http://passportjs.org/guide/authenticate/
return passport.authenticate('google',
// This is the 'custom callback' part
function (err, user, info) {
if (err) {
failure(err);
}
else if (!user) {
failure("Invalid login data");
}
else {
// Here, you can do what you want to control
// access. For example, you asked to deny users
// with a specific email address:
if (user.emails[0].value === "no#emails.com") {
failure("User not allowed");
}
else {
// req.login is added by the passport.initialize()
// middleware to manage login state. We need
// to call it directly, as we're overriding
// the default passport behavior.
req.login(user, function(err) {
if (err) {
failure(err);
}
success();
});
}
}
}
);
};
One idea is to wrap the above code in some more middleware, to make it easier to read:
// This defines what we send back to clients that want to authenticate
// with the system.
var authMiddleware = function(req, res, next) {
var success = function() {
res.send(200, "Login successul");
};
var failure = function(error) {
console.log(error);
res.send(401, "Unauthorized");
};
var middleware = authenticate(req, success, failure);
middleware(req, res, next);
};
// GET /auth/google/return
// Use custom middleware to handle the return from Google.
// The first /auth/google call can remain the same.
app.get('/auth/google/return', authMiddleware);
(This all assumes we're using Express.)
Try this.
googleLogin: function(req, res) {
passport.authenticate('google', { failureRedirect: '/login', scope: ['https://www.googleapis.com/auth/plus.login', 'https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'] }, function(err, user) {
req.logIn(user, function(err) {
if (err) {
console.log(err);
res.view('500');
return;
}
var usrEmail = user['email'];
if(usrEmail.indexOf("#something.com") !== -1)
{
console.log('successful');
res.redirect('/');
return;
}
else
{
console.log('Invalid access');
req.logout();
res.view('403');
return;
}
});
})(req, res);
}
*

Resources