How Do I Authenticate In Sequelize? - node.js

I have a route that I must authenticate by getting sequelize to search for any instance of an existing username and password in the request body in order to know if I can go ahead and authenticate the user. I'm not sure how to do this (search and check instances in Sequelize) because documentation is pretty new for Sequelize. I attempted User.findOne by reading here http://docs.sequelizejs.com/en/latest/api/model/ for example
db.User.findOne({
where: { password: req.password, username: req.username }
}).then(function(address) {
if(address.User !== null) {
console.log('User name: '+address.User.name);
} else {
console.log('User name: NO USER');
}
But not sure of the exact syntax/approach. I have something like this:
app.post('/authenticate', function (req, res) {
//TODO validate req.body.username and req.body.password
//if is invalid, return 401
if (!(req.body.username === 'john.doe' && req.body.password === 'foobar')) {
res.status(401).send('Wrong user or password');
return;
}
var profile = {
first_name: 'John',
last_name: 'Doe',
email: 'john#doe.com',
id: 123
};
// We are sending the profile inside the token
var token = jwt.sign(profile, secret, { expiresIn: 18000 });
res.json({ token: token });
});
app.get('/api/restricted', function (req, res) {
console.log('user ' + req.user.email + ' is calling /api/restricted');
res.json({
name: 'foo'
});
});

Related

JWT Webtoken Unable to verify against req.params

I've created an email authentication system, however there appears to be an issue with how I jwt.verify this token.
I believe there's an issue with my : process.env.PASS_SEC, which is just my Mongo.DB password secret. Is this correct?
I can confirm if I do a res.sent(req.params.token), my token comes through fine, for example in this.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYyZjc0MWU3ZjBkZjZkY2IyZjM0ZDc3ZSIsImlhdCI6MTY2MDM3MTQzMSwiZXhwIjoxNjYwNjMwNjMxfQ.vFtdRzEH2_52Hdhxs84bk7RPdIRDIoZ6Rcd-zZoBhus
As such, I believe it's the SECRET is being passed incorrectly.
My current functioning code is:
router.post("/register", async (req, res, EMAIL_SECRET) => {
const newUser = new User({
fullname: req.body.fullname,
email: req.body.email,
position: req.body.position,
username: req.body.fullname,
password: CryptoJS.AES.encrypt(
req.body.password,
process.env.PASS_SEC
).toString(),
});
const accessToken = jwt.sign(
{
id: newUser._id,
},
process.env.JWT_SEC,
{
expiresIn:"3d"
},
);
const url = `http://localhost:5000/api/auth/confirmation/${accessToken}`;
const mailOptions = {
from: 'nathandrewphone#gmail.com',
to: req.body.email,
subject: 'Confirm Email',
html: `Please click this email to confirm your email: ${url}`
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
try {
const savedUser = await newUser.save();
res.status(201).json(savedUser);
} catch (err) {
res.status(500).json(err);
}
});
Which sends a code fine, however it does not appear to be correct, how would you create an EMAIL_SECRET?
This is how I wish to validate the email.
//User Email Auth Login
//Not yet functioning
router.get('/confirmation/:token', async (req, res) => {
try {
//verify the token with the secret
const { _id: { _id } } = jwt.verify(req.params.token, process.env.PASS_SEC);
await models.User.update({ confirmed: true }, { where: { _id } });
} catch (e) {
res.send('This isnt working');
}
});
However, I cannot get to verify, whats wrong with secret
You signed your token with process.env.JWT_SEC, you should verify it using the same key:
const { _id } = jwt.verify(req.params.token, process.env.JWT_SEC);
Also, you should be able to update your User with findByIdAndUpdate:
await User.findByIdAndUpdate(_id, { confirmed: true });

Separate login auth for admin

I am successfully able to generate login for normal users. Now, I want to have same endpoint /login for my login screen for both normal user and admin. I want to create user-admin with fixed email and flexible password with the token generated will be fixed .
I am new in Node.JS backend routing.
This is my login route:-
router.post('/login' , (req, res, next) => {
User.find({email: req.body.email})
.exec()
.then(user => {
if(user.length < 1) {
return res.status(401).json({
message: "Auth failed. User not found."
})
}
bcrypt.compare(req.body.password, user[0].password, (err, result) =>{
if (err) {
return res.status(401).json({
message: "Auth failed. Check email and password"
});
}
if (result){
const token = jwt.sign(
{
email: user[0].email,
userId: user[0]._id
},
process.env.JWT_KEY,
{
expiresIn : "1h"
});
return res.status(200).json({
message: "Auth Successful",
token : token
});
}
});
})
.catch(err =>{
if (err.code == 500)
res.status(500).send(["Something went wrong in login"]);
else
return next(err);
});
});
What are the things I need to add for my admin portion ?
EDIT:-
user.model
var userSchema = new mongoose.Schema({
fullName : {
type: String,
required: "Full name can't be empty"
},
email : {
type: String,
required: "Email can't be empty",
unique: true
},
password : {
type: String,
required: "Password can't be empty",
minlength: [6 ,"Password must be atleast 6 character long"]
},
phoneNumber : {
type: String,
required: "Reqired for further contact.Can't be empty"
},
saltSecret: String
});
mongoose.model('User', userSchema);
user.controller
const mongoose = require ('mongoose');
const User = mongoose.model('User');
module.exports.register = (req, res, next) =>{
var user = new User();
user.fullName = req.body.fullName;
user.email = req.body.email;
user.password = req.body.password;
user.phoneNumber = req.body.phoneNumber;
user.save((err, doc) =>{
if(!err)
res.send(doc);
else{
if (err.code == 11000)
res.status(422).send(["Entered duplicate email address. Please check"]);
else
return next(err);
}
});
}
You can add an additional field role to the Users collection which can contain values user or admin (Or array of values if there are more roles).
Then, when you create the JWT token, you can add the role field to it.
const token = jwt.sign(
{
email: user[0].email,
userId: user[0]._id,
role: user[0].role
},
process.env.JWT_KEY,
{
expiresIn : "1h"
});
Now, you can use this value to identify if the logged in user is admin or not.
You may need to create a new API for converting a user to admin (change the role field) or do it directly in the database depending on your requirement.
If you want to handle the admin logic entirely through code (without any modification to db) and you already know the email id of the user whom you want to assign as admin, then you can use the following logic.
const adminEmail = "admin#example.com";
const role = user[0].email===adminEmail? "admin" : "user";
const token = jwt.sign(
{
email: user[0].email,
userId: user[0]._id,
role
},
process.env.JWT_KEY,
{
expiresIn : "1h"
});

JWT get user details and set expire time

I am using a JWT token based login system and it is working fine.
But I need to get user details based on JWT token
exports.signin = function(req, res) {
User.findOne({
username: req.body.username
}, function(err, user) {
if (err) throw err;
if (!user || !user.comparePassword(req.body.password)) {
return res.status(401).json({ message: 'Authentication failed. Invalid user or password.' });
}
return res.json({ token: jwt.sign({ email: user.email, username: user.username, _id: user._id }, 'RESTFULAPIs') });
});
};
app.use(function(req, res, next) {
if (req.headers && req.headers.authorization && req.headers.authorization.split(' ')[0] === 'JWT') {
jsonwebtoken.verify(req.headers.authorization.split(' ')[1], 'RESTFULAPIs', function(err, decode) {
if (err) req.user = undefined;
req.user = decode;
next();
});
} else {
req.user = undefined;
next();
}
});
I also need to set the expiration time.
How can I do that?
Ref : NodeJs - Retrieve user infor from JWT token?
exports.me = function(req,res){
if (req.headers && req.headers.authorization) {
var authorization = headers.authorization,
decoded;
try {
decoded = jwt.verify(authorization, secret.secretToken);
} catch (e) {
return res.status(401).send('unauthorized');
}
var userId = decoded.id;
// Fetch the user by id
User.findOne({_id: userId}).then(function(user){
// Do something with the user
return res.send(200);
});
}
return res.send(500);
}
Ref: For token expiration / extending it JWT (JSON Web Token) automatic prolongation of expiration
Web applications
A good pattern is to refresh the token before it expires.
Set the token expiration to one week and refresh the token every time the user open the web application and every one hour. If a user doesn't open the application for more than a week, they will have to login again and this is acceptable web application UX.
To refresh the token your API needs a new endpoint that receives a valid, not expired JWT and returns the same signed JWT with the new expiration field. Then the web application will store the token somewhere
Modify Your code as follow:-
exports.signin = function (req, res) {
User.findOne({
username: req.body.username
}, function (err, user) {
if (err) throw err;
if (!user || !user.comparePassword(req.body.password)) {
return res.status(401).json({ message: 'Authentication failed. Invalid user or password.' });
}
let NumberOfDayInMiliSec = 1000 * 60 * 60 * 24 * 1 //One Day
return res.json({ token: jwt.sign({ exp: Date.now() + NumberOfDayInMiliSec, email: user.email, username: user.username, _id: user._id }, 'RESTFULAPIs') });
});
};
app.use(function (req, res, next) {
if (req.headers && req.headers.authorization && req.headers.authorization.split(' ')[0] === 'JWT') {
jsonwebtoken.verify(req.headers.authorization.split(' ')[1], 'RESTFULAPIs', function (err, decode) {
if (err) req.user = undefined;
if (decode.exp < Date.now()) {
return res.status(400).json({ status: false, msg: "Token expired" });
}
req.user = decode;
next();
});
} else {
req.user = undefined;
next();
}
});

JWT error with placement of jwt.sign code

I'm working on creating a authentication system and am trying to figure out how to use JWT. I'm using Node, express, passport and MYSQL. I tried creating the "var token" after the db.sync() method but that would only throw a error but then it works if i put the "var token" before db.sync() why is this? And should i do it this way? Thanks in advance!
var jwt = require('jsonwebtoken');
var config = require('../config'),
db = require('../services/database'),
User = require('../models/user'),
Organisation = require('../models/organisation'),
Event = require('../models/event');
// The authentication controller.
var AuthController = {};
// Register a user.
AuthController.signUp = function(req, res) {
if(!req.body.username || !req.body.password || !req.body.email) {
res.json({ message: 'Please provide a username and a password.' });
} else {
var token = jwt.sign({ username: req.body.username }, config.keys.secret, { expiresIn: '30m' });
db.sync().then(function() {
var newUser = {
username: req.body.username,
password: req.body.password,
email: req.body.email,
temporarytoken: token
};
console.log(newUser.temporarytoken);
return User.create(newUser).then(function() {
res.status(201).json({ message: 'Account created!' });
});
}).catch(function(error) {
res.status(403).json({ message: 'Username already exists!' });
});
}
}
What is your error message like?
Also, are you seeing errors if you do this code?
db.sync().then(function() {
var token = jwt.sign({ username: req.body.username }, config.keys.secret, { expiresIn: '30m' });
var newUser = {
username: req.body.username,
password: req.body.password,
email: req.body.email,
temporarytoken: token
};
console.log(newUser.temporarytoken);
return User.create(newUser).then(function() {
res.status(201).json({ message: 'Account created!' });
});
P.S. Why are you saving the token to the DB? You should send the jwt to the client and the client will save it to a local storage or cookie. That is the whole point of jwt.

Selecting from mongodb object returns undefined

I'm trying to build some auth and after successful auth I can't access values inside object inside object in mongodb, it returns undefined. Is there any thing I need to know about mongodb objects?
Here's my code:
app.post('/user/auth', function (req, res) {
// find the user
console.log('requested stuff is ' + req.body.username + ' and ' + req.body.password)
User.find({
'data.username': req.body.username,
'data.password': req.body.password
}, function (err, user) {
console.log(user) // returns { _id: 59085883734d1d3098a83590, data: { username: 'admin1', password: 'password', email: 'email' }, profile: { nickname: 'workingNickname' } }
console.log(user.data) // returns undefined
console.log(user['data']) // returns undefined
if (err) throw err;
if (!user) {
res.send('User not found with' + req.body.username);
} else if (user) {
// check if password matches
if (user.password != req.body.password) {
res.send('Password wrong. Auth failed');
} else {
// if user is found and password is right
// create a token
var token = jwt.sign(user, app.get('superSecret'), {
expiresIn: 60 * 60 * 24 // expires in 24 hours
});
// return the information including token as JSON
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
}
});
});

Resources