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.
Related
im completing a fullstack project using react and node
when trying to register a user or a product i keep on getting error 500 in the browser and this error in my visual studio terminal:
Error: Illegal arguments: string, object
here's my create user function:
const createUser = asyncHandler(async (req, res) => {
const { name, email, password } = req.body;
const userExist = await User.findOne({ email });
if (userExist) {
res.status(400);
throw new Error("User already exists");
}
const user = await User.create({
name,
email,
password,
});
if (user) {
res.status(201).json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user._id),
});
} else {
res.status(400);
throw new Error("Invalid user data");
}
});
what could cause an error 500?
trying to register a new user to the db
To resolve this issue you can follow some steps:
Try to console the data from the request parameters i.e name, email, password and manipulate your request parameters
Else use:- const email=req.body.email; such syntax for all the request params
Again try to console the req params, hope this time these params will be there.
Use this modification:
const createUser = asyncHandler(async (req, res) => {
const name = req.body.name;
const email = req.body.email;
const password = req.body.password;
const userExist = await User.findOne({ email });
if (userExist) {
res.status(400);
throw new Error("User already exists");
}
const user = await User.create({
name,
email,
password,
});
if (user) {
res.status(201).json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user._id),
});
} else {
res.status(400);
throw new Error("Invalid user data");
}
});
if your req params are not accessing the body params from the form, try using body-parser or multer for the same.
Note: Try using console.log() to know the line of concern of your code.
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 });
node js
This is my register method to register a user. I am trying to pass token in headers when a user is registered which will be used in the front end to access the token and store it in the local storage.
module.exports.register = async function (req, res, next) {
try {
const { username, email, password } = req.body;
const profileImage = req.file.path;
const usernameCheck = await User.findOne({ username });
if (usernameCheck)
return res.json({ msg: "Username already used", status: false });
const emailCheck = await User.findOne({ email });
if (emailCheck)
return res.json({ msg: "Email already exists", status: false });
const hashedPassword = await bcrypt.hash(password, 10);
const user = await User.create({
_id: new mongoose.Types.ObjectId(),
username,
email,
profileImage,
password: hashedPassword,
});
delete user.password;
//create jwt token
const token = jwt.sign(
{
username: user.username,
email: user.email,
userId: user._id,
},
process.env.JWT_KEY,
{
expiresIn: "1h",
}
);
res.header("x-auth-token", token); //This is not setting the token in headers
return res.json({
message: "User Created Successfully",
status: true,
user,
});
} catch (ex) {
next(ex);
}
};
react js
This is my front-end react code to register a user. I want to login the user with the jwt token stored in localStorage once the user is registered.
const handleSubmit = async (values) => {
try {
const { username, email, profileImage, password } = values;
const formData = new FormData();
formData.append("username", username);
formData.append("email", email);
formData.append("profileImage", profileImage);
formData.append("password", password);
const response = await register(formData);
console.log(response);
if (response.status === false) return;
else {
loginWithJwt(response.headers["x-auth-token"]);// log the user in using jwt token
console.log(response.headers["x-auth-token"]);
navigate("/chatroom");
}
} catch (ex) {
console.log(ex.message);
}
};
I'm trying to make a login function that receives and email and password from user.
checks if email exists - works
checks if password match to encrypted password in db - works
if 1+2 is true -> generates a token and set the token into the user document. But it doesn't work, the action user.token = token is invalid, and postman yields no response.
what am I doing wrong?
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('../models/user');
exports.login = async (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
let emailExist = await User.findOne({ email: email }).then(user => {
if (!user) {
return res.json({ isAuth: false, message: 'Login failed, email not found' });
}
return user;
});
let isPasswordMatch = await bcrypt.compare(password, emailExist.password);
if (!isPasswordMatch) {
return res.json({ isAuth: false, message: 'Login failed, wrong password' });
}
let loadedUser = await User.findOne({ email: email, password: emailExist.password })
.then(user => {
if (!user) {
return res.json({ isAuth: false, message: 'Login failed' });
}
return user;
})
.then(user => {
const token = jwt.sign({ role: user.role, email: user.email, userId: user._id.toString() }, 'secret');
console.log(user);
user.token = token;
return user.save();
});
res.status(200)
.cookie(('auth', token))
.json({ isAuth: true, token: token, user: loadedUser });
};
updated version: (still doesn't work)
now it gives me the following error:
(node:11336) UnhandledPromiseRejectionWarning: CastError: Cast to
number failed for value
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjowLCJlbWFpbCI6ImFoQGdtYWlsLmNvbSIsInVzZXJJZCI6IjVjMTc4NDc3Mzg5MWI5MjY5MGNkMzgwNiIsImlhdCI6MTU0NTA1MTY5OX0.8GWuV82A7yOvKKkXeOjIeYve5aH0YwBEK_RuH0NVfYA"
at path "token"
exports.login = async (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
let emailExist = await User.findOne({ email: email });
if (!emailExist) {
return res.json({ isAuth: false, message: 'Login failed, email not found' });
}
let isPasswordMatch = await bcrypt.compare(password, emailExist.password);
if (!isPasswordMatch) {
return res.json({ isAuth: false, message: 'Login failed, wrong password' });
}
let loadedUser = await User.findOne({ email: email, password: emailExist.password });
let token = jwt.sign(
{
role: loadedUser.role,
email: loadedUser.email,
userId: loadedUser._id.toString()
},
'secret'
);
console.log('token === ', token);
console.log('user before token === ', loadedUser);
updateUserToken = await loadedUser.update({ $set: { token: token } });
console.log('user === ', loadedUser);
res.status(200)
.cookie(('auth', token))
.json({ isAuth: true, token: token, user: updateUserToken });
};
check your user model file and see whether you have add the token as a number. if so this might be the issue. Try changing it to string
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'
});
});