undefined jwt token react/express - express

I am implementing a JWT authentication on a login/registration system. When there is a successful login/registration I am setting a user token in localStorage.
Problem is when I check my localStorage the user key is present but the value is undefined. I think the issue might be in my axios post or in my express file but I can't quite figure it out.
// my action creator
export function login(user, history) {
return async (dispatch) => {
axios.post('/api/login', { user })
.then(res => {
dispatch({ type: AUTHENTICATED });
localStorage.setItem('user', res.data.token);
history.push('/');
})
.catch((error) => {
dispatch({
type: AUTHENTICATION_ERROR,
payload: 'Invalid email or password'
});
});
};
}
The data is reaching my api correctly. The item is being set but the value res.data.token is undefined.. Below is my express file
// login.js (/api/login)
router.post('/', function(req, res) {
var email = req.body.user.email;
var password = req.body.user.password;
// TODO: create db file and import connection
var connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "dbname",
port: 3307
});
connection.connect(function(err) {
if(err) {
console.log(err);
} else {
connection.query("SELECT ID, Password FROM Users WHERE Email = ?", [email], function(err, result) {
if(err) {
console.log('Could not find account');
res.send(err);
} else {
var id = result[0].ID;
bcrypt.compare(password, result[0].Password, function(err, result) {
if(result) {
console.log(id);
res.json({ id });
} else {
console.log('Incorrect password');
}
});
}
});
}
});
});
Since the res.data.token in my action creator is returning undefined does that mean the response in my express file ( res.json([id]) ) is just returning defined?

You are not sending the response properly.
res.json([id]); Its just sending the array of id. That's why res.data.token is undefined. as data does not contain an object.
Send proper object like:
res.json({id});

Related

How do I handle passport js redirects from Nuxt SSR?

I am using Nuxt SSR with express session and I have a passport JS redirect from the server side
/**
* POST /signup
* Create a new local account.
*/
exports.postSignup = (req, res, next) => {
const validationErrors = [];
if (!validator.isEmail(req.body.email)) validationErrors.push({ msg: 'Please enter a valid email address.' });
if (!validator.isLength(req.body.password, { min: 8 })) validationErrors.push({ msg: 'Password must be at least 8 characters long' });
if (req.body.password !== req.body.confirmPassword) validationErrors.push({ msg: 'Passwords do not match' });
if (validationErrors.length) {
req.flash('errors', validationErrors);
return res.redirect('/signup');
}
req.body.email = validator.normalizeEmail(req.body.email, { gmail_remove_dots: false });
const user = new User({
email: req.body.email,
password: req.body.password
});
User.findOne({ email: req.body.email }, (err, existingUser) => {
if (err) { return next(err); }
if (existingUser) {
req.flash('errors', { msg: 'Account with that email address already exists.' });
return res.redirect('/signup');
}
user.save((err) => {
if (err) { return next(err); }
req.logIn(user, (err) => {
if (err) {
return next(err);
}
res.redirect('/');
});
});
});
};
If I call the redirect method? it would reload the page and clear Vuex state right?
How do I do this redirect from passport such that Vuex state is kept intact and client page does not refresh
It is indeed better to asynchronously handle form submissions to avoid page refresh as #Darius mentioned. But for completion's sake I'd like to mention that solutions do exist to persist your Vuex state, such as vuex-persistedstate.
It can be used to persist the state to localStorage, sessionStorage, or even cookies. It can also be used as a Nuxt plugin.

Problem with logout user. Express server api with JWT auth

I'm trying to create a full-stack mern app. I use jwt authentication. I will save the token in local storage and the token will be removed from there with react.
I have tried with req.logout(), req.logOut() and req.session.destroy() and it doesn't work.
Thank you!
const signIn = (req, res) => {
const { email, password } = req.body;
User.findOne({ email: email })
.then((user) => {
if (!user) {
const error = new Error('A user with this email could not be found');
error.statusCode = 401;
throw error;
}
if(!user.authenticate(password)) {
const error = new Error('A user with this email could not be found');
error.statusCode = 401;
throw error;
}
const token = jwt.sign({
email: user.email,
userId: user._id.toString()
}
, 'somesupersecret'
, { expiresIn: '1h' });
res.status(200).json(
{
message: 'User successfully logged in!',
token,
userId: user._id.toString()
});
})
.catch(error => {
if (!error.statusCode) {
error.statusCode = 500;
next(error);
}
})
}
const logOut = async(req, res) => {
try{
await req.logOut();
res.status(200).json(
{
message: 'User successfully logged out!',
});
}
catch(error) {
console.log(error);
}
}
module.exports = {
signUp,
signIn,
logOut
}
I become errors like TypeError: req.logOut is not a function.
This should not be done on the server. Just remove/invalidate your jwt token that is being sent by the client. Generally the token is stored in localStorage and/or cookies. Just delete that token and refresh the page, user will logout.

Bcrypt + Sequelize password not saving as hash in DB

Sequelize + Bcrypt not storing passwords in DB as hash
As the title says, whenever I attempt to store a user into my SQLite DB the console outputs the password as a hash but when I look into the DB with DBbrowser I can see the plaintext password.
Model
// const Promise = require('bluebird')
const bcrypt = require('bcrypt')
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
}, {
hooks: {
beforeSave: hashPassword,
beforeCreate: hashPassword
}
})
User.prototype.comparePassword = function (password) {
bcrypt.compare(password, this.password, function (res, err) {
if (res) {
console.log(res)
} else {
console.log(err)
}
})
return bcrypt.compare(password, this.password)
}
return User
}
Controllers
module.exports = {
async register (req, res) {
try {
const user = await User.create(req.body)
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (err) {
// e-mail already exists or such
res.status(400).send({
error: 'This email address is already in use'
})
}
},
async login (req, res) {
try {
// Grab user input
const { email, password } = req.body
const user = await User.findOne({
where: {
email: email
}
})
// Check to see if user is in db
if (!user) {
res.status(403).send({
error: 'the login information was incorrect / Not Found'
})
}
// Check to see if password is valid
const isPasswordValid = await user.comparePassword(password)
if (!isPasswordValid) {
return res.status(403).send({
error: 'The login information was incorrect'
})
}
// return user using toJSON()
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (e) {
res.status(500).send({ error: 'An error occured attempting to login' })
console.log(e)
}
}
}
To elaborate a little more, whenever I create a user, I receive the following:
{
"user": {
"id": 1,
"email": 'test#test.com",
"password": "$2b$08$SYYXU/GDSCFsp3MVeuqrduI0lOLHeeub7whXiaMMoVxO53YJry.1i",
"updatedAt": "2018-09-07T22:44:12.944Z",
"createdAt": "2018-09-07T22:44:12.944Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJTVVBCUkhVQGxvbC5jb20iLCJwYXNzd29yZCI6IiQyYiQwOCRTWVlYVS9HRFNDRnNwM01WZXVxcmR1STBsT0xIZWV1Yjd3aFhpYU1Nb1Z4TzUzWUpyeS4xaSIsInVwZGF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImNyZWF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImlhdCI6MTUzNjM2MDI1MywiZXhwIjoxNTM2OTY1MDUzfQ.mDaeIikzUcV_AGTuklnLucx9mVyeScGpMym1y0kJnsg"
}
Which to me says the DB successfully hashed my password, and stored it. The overhanging issue for me with this is the fact that I believe it's causing the bcrypt.compare function to spit out 'false'. As always, any insight or help would be greatly appreciated!
I'm pretty sure that this answer is too late for you, but might help others landing on this same question.
The main issue I can see is how you are using the async/await pattern. Changing this:
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
to this, worked for me:
async function hashPassword(user, options) {
if (!user.changed("password")) {
return 0;
}
user.password = await bcrypt.hash(user.password, SALT_FACTOR);
}
Can you please try to add only one hook
hooks: {
beforeSave: hashPassword,
}
Because I think your password is getting hashed two times. as beforeSave and beforeCreate both hooks get executed.
Hope it helps

User in Passport Authentication Custom Callback is always false

I'm trying to use local authentication with Passport and Express, and I have two separate routes to log in: one for the website, which does a redirect, and one for the mobile app which I want to return a JSON object. The redirect route works. However, POSTing the same username and password to the other route receives the JSON response for a failed login. My LocalStrategy is as follows:
passport.use('local-signin', new LocalStrategy(
{passReqToCallback : true},
function(req, username, password, done) {
funct.localAuth(username, password)
.then(function (user) {
if (user) {
console.log("LOGGED IN AS: " + user.username);
req.session.success = 'You are successfully logged in ' + user.username + '!';
return done(null, user);
}
if (!user) {
console.log("COULD NOT LOG IN");
req.session.error = 'Could not log user in. Please try again.'; //inform user could not log them in
return done(null, false, { message: 'User not found' });
}
})
.fail(function (err){
console.log(err.body);
return done(err);
});
}
));
and these are the two places I use it:
app.post('/login', passport.authenticate('local-signin', {
successRedirect: '/',
failureRedirect: '/signin'
})
);
app.post('/api/login', function(req, res, next) {
passport.authenticate('local-signin', function(err, user, info) {
if (err) {
return res.json(user);
}
if (!user) {
return res.json(true);
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
return res.json(user);
});
})
(req, res, next);
});
I get the success redirect from './login', but './api/login' replies with 'true' (the JSON response I have set for if 'user' is 'false'). This doesn't make any sense to me, but I can't find any problem with the code.
Any idea what the issue here could be? Thanks.

How to redirect after http basic auth to same url

I am able to bring a username and password pop up whenever i hit the url but i am able to verify the details with the one's present in database but not redirect it to same handler. It is stucking in else loop. How to do that ? After verifying if the logged in person has the right scope then it will give you response data.
My Server.js -
const simple_validate = function (request, reply, next) {
var credentials = auth(request);
if (!credentials || credentials.name !== 'john' || credentials.pass !== 'secret') {
reply('Not authorized').code(401);
reply().header('WWW-Authenticate', 'Basic realm="example"').hold();
reply('success');
} else {
next();
reply('Access granted');
}
}
server.register(Basic, (err) => {
server.auth.strategy('simple', 'basic', { validateFunc: simple_validate });
});
This is the right way of doing it.
const validate = function (request, email, password, callback) {
// validate your email and password here
User.findUser(email,password,function(err,result){
if(err)
callback(null,false);
else
//do whatever you wanna do
});
}
server.register(require('hapi-auth-basic'), (err) => {
server.auth.strategy('simple', 'basic', {
validateFunc: validateApi
});
});