Hello guys I have a problem trying to get my user session with passport on reactjs. I have no problem to get on post man , I cannot fetch the data with a Get method on react js, im getting undefined:(.
I configurated my cors and everything and still no data :(.
This is my fetch
const [user, setUser] = useState(null);
useEffect(() => {
const getUser = async () => {
try {
const response = await axios.get("http://localhost:8080/login/success");
const data = await response.json();
setUser(data);
} catch (error) {
throw new Error(`error fetching data ${error}`);
}
};
getUser();
}, []);
and this is my end point and passport js config.
function checkAuthentication(req, res, next) {
if (req.isAuthenticated()) next();
else {
res.status(401).json({
message: "Failure",
});
}
}
router.get("/login/success", checkAuthentication, (req, res) => {
if (req.user) {
res.status(200).json({
success: true,
message: "success user",
user: req.user,
});
console.log(req.user);
} else {
req.status(404).json({
success: false,
message: "No user",
})
}
});
passport.use(
"login",
new LocalStrategy(async (username, password, done) => {
try {
const user = await User.findOne({ username: username });
if (!user) {
return done(null, false, { message: "Incorrect username" });
}
const isMatch = await user.isValidPassword(password);
if (!isMatch) {
return done(null, false, { message: "Incorrect password" });
} else {
return done(null, user, { message: "Logged in successfully" });
}
} catch (error) {
console.log(error);
}
})
);
Related
router.post("/auth", async (req, res) => {
const { username, password } = req.body;
const user = await login.findOne({ where: { username: username } });
if (!user) res.json({ error: "User Doesn't Exist" });
bcrypt.compare(password, user.password).then((match) => {
if (!match) res.json({ error: "Wrong Username And Password Combination" });
res.json("YOU LOGGED IN!!!");
});
})
module.exports = router;enter image description here
This error was due to not catching errors properly the correct way of catching errors will be like:
router.post("/auth", async (req, res) => {
const { username, password } = req.body;
const user = await login.findOne({
where: { username: username }
});
if (!user)
res.json({ error: "User Doesn't Exist" })
else {
bcrypt
.compare(password, user.password)
.then((match) => {
if (!match)
res.json({ error: "Wrong Username And Password Combination" })
else {
res.json("Logged in");
}
});
}
})
module.exports = router;
Picture of error in postman
//This is route
router.get("/all/posts",isSignedIn,isAuthenticated, getAllPosts)
//This is controller
exports.getAllPosts = (req, res) => {
Post.find()
.populate("postedBy","_id username")
.exec((err, posts) => {
if(err || !posts){
return res.status(400).json({
error:"No Post found"
})
}
res.json(posts)
})
}
//This is Auth controller which is middleware where I'm getting error
exports.isAuthenticated = (req, res, next) => {
let checker = req.profile && req.auth && req.profile._id == req.auth._id;
if (!checker) {
console.log(checker);
return res.status(403).json({
error: "ACCESS DENIED",
});
}
console.log(checker);
next();
};
//This is isSignedIn controller
//protected routes
exports.isSignedIn = expressJwt({
secret: process.env.SECRET,
userProperty: "auth",
});
//This is signin controller
exports.signin = (req, res) => {
const errors = validationResult(req);
const { username, password } = req.body;
if (!errors.isEmpty()) {
return res.status(422).json({
error: errors.array()[0].msg,
});
}
User.findOne({ username }, (err, user) => {
if (err || !user) {
return res.status(400).json({
error: "USER does not exists",
});
}
if (!user.autheticate(password)) {
return res.status(401).json({
error: "Username and password do not match",
});
}
//create token
const token = jwt.sign({ _id: user._id }, process.env.SECRET);
//put token in cookie
res.cookie("token", token, { expire: new Date() + 9999 });
//send response to front end
const { _id, username, role } = user;
return res.json({ token, user: { _id, username, role } });
});
};
//Only all/posts having problem remaining all are working fine even isAuthentication is also working with others routes but in this case it is giving error
I am working on small node api and I have an issue with patch method.
My router.patch is returning me 404.
This is how my route looks:
router.param('userId', findById);
router.patch(
'/api/projects/update/:projectId/:userId',
authCheck,
isAdmin,
findProjectById,
update
);
The findById is based on my :userId param. Whole method looks like this:
exports.findById = async (req, res, next) => {
try {
let user = await User.findById(req.params.userId);
if (!user) return res.status(400).json({ msg: 'User not found' });
next();
} catch (err) {
console.error(err.message);
if (err.kind === 'ObjectId') {
return res.status(400).json({ msg: 'User not found' });
}
res.status(500).send('Server Error');
}
};
Based on that I should get proper user for proper project.
My two ayhorization methods:
exports.authCheck = async (req, res, next) => {
try {
/* get token from header
replace('Bearer', '') - this will remove bearer from token header
*/
const token = req.header('Authorization').replace('Bearer', '');
//check if no token
if (!token) {
return res.status(401).json({ msg: 'No token, authorization denied' });
}
/*
decoded contains _id as a payload in token. Id is from getAuthToken */
const decoded = jwt.verify(token, config.get('jwtSecret'));
const user = await User.findOne({
_id: decoded._id,
'tokens.token': token,
});
if (!user) {
throw new Error();
}
req.token = token;
req.user = user;
next();
} catch (err) {
res.status(401).json({ msg: 'Please authenticate' });
}
};
exports.isAdmin = async (req, res, next) => {
try {
if (req.user.role !== config.get('roleSecret')) {
return res.status(403).json({
errors: [
{
msg: 'No Admin rights. Access Denied!!',
},
],
});
}
next();
} catch (err) {
res.status(403).json({ msg: 'Forbidden access' });
}
};
Finaly, my project controller where i have findProjectById, update
In findProjectById I am looking for project based on route param and i assing it to project
exports.findProjectById = async (req, res, next) => {
const _id = req.params.projectId;
try {
let project = await Project.findById(_id);
if (!project) return res.status(400).json({ msg: 'Porject not found' });
req.project = project;
next();
} catch (err) {
console.error(err.message);
if (err.kind === 'ObjectId') {
return res.status(400).json({ msg: 'Porject not found' });
}
res.status(500).send('Server Error');
}
};
My update method i s not done, because i was testing if anything heppens
exports.update = async (req, res) => {
try {
const proj = await req.project;
const _id = proj._id;
await Project.findByIdAndUpdate(_id, req.body, {
new: true,
runValidators: true,
});
if (!proj) {
return res.status(404).json({ msg: 'Project not found' });
}
return res.json(proj);
} catch (err) {
res.status(500).send('Server Error');
}
};
Not sure what am I missing here, but after few hours and lot of searching still can't get this working
Get this working. Issue was in my router path.
/api/projects/update/:projectId/:userId
Should be
/projects/update/:projectId/:userId
this can be closed
I am learning Node Js and express as ORM i need to create user authorization and i have managed to create signup backend code and tested it via postman and it work perfect, the challenge come with login, when i test it via postman i get an this error in my vscode terminal "TypeError: Cannot read property 'password' of undefined" I have tried to find out but many solution state there is a problem with sequelize order, that app.use(bodyParser.json()); should come first before routes and my order are correct but still a get the same error. please who can help me
My user (signup and login code)
const express = require('express');
const bcrypt = require('bcrypt');
const User = require('../models/users');
const router = express.Router();
router.post('/signup',(req, res, next)=>{
User.findOne({
where:{
email:req.body.email
}
}).then(user=>{
if(user){
res.status(409).json({
message:'Email alreadly exist!'
})
}else{
bcrypt.hash(req.body.password, 10, (err, hash)=>{
if(err){
return res.status(500).json({
error:err
});
}else{
const user =new User({
email:req.body.email,
password: hash
});
user.save()
.then(result=>{
// console.log(result)
res.status(201).json({
message:'User created successfully'
});
})
.catch(err=>{
console.log(err);
res.status(500).json({
error:err
});
});
}
})
}
})
});
router.post('/login',(req, res, next)=>{
User.findOne({
where:{
email:req.body.email
}
})
.then(user =>{
if(user.length<1){
return res.status(401).json({
message:'Authentication failed'
});
}
bcrypt.compare(req.body.password, user[0].password, (err, result)=>{
if(err){
return res.status(401).json({
message:'Authentication failed'
});
}
if(result){
return res.status(200).json({
message:'Authorization granted!'
});
}
return res.status(401).json({
message:'Authentication failed'
});
});
})
.catch(err=>{
console.log(err);
res.status(500).json({
error:err
});
});
});
module.exports=router;
my app.js code
const express = require('express');
const app= express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
const productRoutes = require('./api/routes/products');
const orderRoutes = require('./api/routes/orders');
const userRoutes =require('./api/routes/users');
const sequelize =require('./api/config/database');
app.use((req, res, next)=>{
res.header('Access-Control-Allow-Origin','*');
res.header('Access-Control-Allow-Headers','Origin, X-Requested, Content-Type, Accept, Authorization');
if(req.method === 'OPTIONS'){
res.header('Access-Control-Allow-Methods','PUT, POST, GET, DELETE');
return res.status(200).json({
});
}
next();//this allow our request to procede
});
app.use('/products',productRoutes);
app.use('/orders',orderRoutes);
app.use('/users',userRoutes);
app.use((req, res, next)=>{
const error =new Error('Page Not Found');
error.status=404;
next(error);
});
app.use((error, req, res, next)=>{
res.status(error.status||500);
res.json({
error:{
message:error.message
}
});
});
sequelize.sync().then(result=>{
// console.log(result);
})
.catch(err=>{
console.log(err);
});
module.exports=app;
this is pc from postman
Register and login routes
const express = require('express');
const bcrypt = require('bcrypt');
const User = require('../models/users');
const router = express.Router();
router.post('/signup',(req, res, next)=>{
User.findOne({
where:{
email:req.body.email
}
}).then(user=>{
if(user){
res.status(409).json({
message:'Email alreadly exist!'
})
}else{
bcrypt.hash(req.body.password, 10, (err, hash)=>{
if(err){
return res.status(500).json({
error:err
});
}else{
const user =new User({
email:req.body.email,
password: hash
});
user.save()
.then(result=>{
// console.log(result)
res.status(201).json({
message:'User created successfully'
});
})
.catch(err=>{
console.log(err);
res.status(500).json({
error:err
});
});
}
})
}
})
});
router.post('/login', async (req, res, next) => {
console.log("req.body: ", req.body);
try {
if (!req.body.email || !req.body.password) {
console.log("Email and password not given");
return res.status(400).send("Email and password is required");
}
const { email, password } = req.body;
let user = await User.findOne({ email });
if (!user) {
console.log("user not found");
return res.status(401).json({ message: 'Authentication failed' });
}
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) {
console.log("Password is not valid");
return res.status(401).json({ message: 'Authentication failed' });
}
return res.status(200).json({ message: 'Authorization granted!' });
}
catch (err) {
console.log("Err: ", err);
res.status(500).json({ error: err });
}
});
module.exports=router;
this is my db, model and server
const http = require('http');
const app = require('./app');
const PORT = process.env.PORT||4000;
const server =http.createServer(app);
server.listen(PORT);
user model
const Sequelize = require('sequelize');
const sequelize = require('../config/database');
const User = sequelize.define('users',{
id:{
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey:true
},
email:{
type: Sequelize.STRING(50),
required: true,
notEmpty:true,
validate:{
isEmail:true,
},
unique:'email'
},
password:{
type: Sequelize.STRING(30),
required: true
}
});
module.exports=User;
db
const Sequelize = require('sequelize');
const sequelize =new Sequelize('projectone','root','',{
dialect: 'mysql',
host: 'localhost'
});
module.exports=sequelize;
this is user routes for signup and login
const express = require('express');
const bcrypt = require('bcrypt');
const User = require('../models/users');
const router = express.Router();
router.post('/signup', async (req, res, next) => {
try {
const { email, password } = req.body;
let user = await User.findOne({where:{email}});
if (user) return res.status(409).json({ message: 'Email already exist!' });
user = new User({ email, password });
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
await user.save();
res.status(201).json({ message: 'User created successfully' });
}
catch (err) {
console.log(err);
res.status(500).json({
error: err
});
}
});
router.post("/login", async (req, res, next) => {
try {
if (!req.body.email || !req.body.password) {
return res.status(400).send("Email and password is required");
}
const { email, password } = req.body;
let user = await User.findOne({ where: { email } });
if (!user) {
console.log("user not found");
return res.status(401).json({ message: "Authentication failed" });
}
const validPassword = await bcrypt.compare(password, user.get("password"));
if (!validPassword) {
console.log("Password is not valid");
return res.status(401).json({ message: "Authentication failed" });
}
return res.status(200).json({ message: "Authorization granted!" });
} catch (err) {
console.log("Err: ", err);
res.status(500).json({ error: err });
}
});
module.exports=router;
Can you try this login route, I converted code using async/await and handled all the possibilities, even the problem still exists it will give you all the information what is wrong.
note that after finding the user, password can be retrieved from user.get("password") like this:
router.post("/login", async (req, res, next) => {
try {
if (!req.body.email || !req.body.password) {
return res.status(400).send("Email and password is required");
}
const { email, password } = req.body;
let user = await User.findOne({ where: { email } });
if (!user) {
console.log("user not found");
return res.status(401).json({ message: "Authentication failed" });
}
const validPassword = await bcrypt.compare(password, user.get("password"));
if (!validPassword) {
console.log("Password is not valid");
return res.status(401).json({ message: "Authentication failed" });
}
return res.status(200).json({ message: "Authorization granted!" });
} catch (err) {
console.log("Err: ", err);
res.status(500).json({ error: err });
}
});
And your signup route can be refactored to async/await like this:
router.post('/signup', async (req, res, next) => {
try {
const { email, password } = req.body;
let user = await User.findOne({where:{email}});
if (user) return res.status(409).json({ message: 'Email already exist!' });
user = new User({ email, password });
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
await user.save();
res.status(201).json({ message: 'User created successfully' });
}
catch (err) {
console.log(err);
res.status(500).json({
error: err
});
}
});
I have modified your code and put some comments on it. Please try:
Signup route
router.post('/signup',(req, res, next)=>{
return User.findOne({
where:{
email:req.body.email
}
}).then(user=>{
if(user){
res.status(409).json({
message:'Email alreadly exist!'
})
}else{
bcrypt.hash(req.body.password, 10, (err, hash)=>{
if(err){
return res.status(500).json({
error:err
});
}else{
return User.create({
email: req.body.email,
password: hash
})
.then(result=>{
// console.log(result)
res.status(201).json({
message:'User created successfully'
});
})
.catch(err=>{
console.log(err);
res.status(500).json({
error:err
});
});
}
})
}
})
});
Signin route
router.post('/login',(req, res, next)=>{
// .findOne does not return an array and you need to return this Promise to be chainable
return User.findOne({
where:{
email: req.body.email
}
})
.then(user =>{
if(!user) { // User not found!
console.log(`User with ${req.body.email} not found!`);
return res.status(401).json({
message:'Authentication failed'
});
}
const u = user.toJSON();
console.log('User data from DB:', u);
// Changed `user[0].password` to `u.password`
bcrypt.compare(req.body.password, u.password, (err, result)=> {
if(err){
console.error('Error during comparison!', err);
return res.status(401).json({
message:'Authentication error'
});
}
if(result){
console.log('Authentication success!');
return res.status(200).json({
message:'Authorization granted!'
});
}
return res.status(401).json({
message:'Authentication failed'
});
});
})
.catch(err=>{
console.log(err);
res.status(500).json({
error:err
});
});
});
I'm currently making app with vue & express.
I adopted passport as authentication library and I've used it several times.
so I know that when I make login request, passport middleware authenticates user by 'xx strategy'.
The problem is register request works well but login isn't.
I constantly get 'false' for response.data.
I can't even guess where the false comes from.
There is no return statements that returns false.
follow is my code.
passport.deserializeUser((authId, done) => {
let hasUser
let users = User.findOneByAuthId(authId)
.then(results => (hasUser = results.length))
if (hasUser) {
console.log('deserialize!')
done(null, users[0])
} else {
console.log('no user')
done(null, { message: 'no user' })
}
})
passport.use(new LocalStrategy(
(username, password, done) => {
let hasUser
let users = User.findOneByEmail(username)
.then(results => (hasUser = results.length))
if (hasUser) {
let user = users[0]
let { hash } = user
if (User.checkPassword(password, hash)) {
done(null, { message: 'success' })
} else {
done(null, { message: 'wrong password' })
}
} else {
done(null, { message: 'wrong email' })
}
}
))
router.post('/register', (req, res) => {
if (!fun.emailChecker(req.body.username)) {
return res.status(403).json({
message: 'Invalid Email'
})
}
if (!fun.passwordChecker(req.body.password)) {
return res.status(403).json({
message: 'Invalid Password'
})
}
let hasUser
User.findOneByEmail(req.body.username)
.then(results => (hasUser = results.length))
if (hasUser) {
return res.status(409).json({
message: 'Email Exist'
})
} else {
let user = {
authId: 'local: ' + req.body.username,
email: req.body.username,
hash: User.hashPassword(req.body.password),
displayName: req.body.displayName
}
User.create(user)
.then(results => {
if (!results) {
throw new Error('user creation error')
} else {
req.login(user, err => {
if (!err) {
req.session.save(() => {
return res.json({ success: true })
})
}
})
}
})
}
})
router.post('/login', (req, res) => {
passport.authenticate('local', (err, result) => {
if (!err) {
return res.json(result)
}
})(req, res)
})
// vue component
methods: {
onSubmit () {
axios.post('http://localhost:3001/auth/login', {
email: this.email,
password: this.password
}).then(response => console.log(response.data))
},
There are various issues with your code.
Starting with incorrect promise handling:
let hasUser
let users = User.findOneByAuthId(authId)
.then(results => (hasUser = results.length))
if (hasUser) { ... }
You are trying to make asynchronous code synchronous here. The code that depends on the result of the asynchronous query has to be moved to inside the then handler (both in deserializeUser and the strategy verification handler):
User.findOneByAuthId(authId).then(users => {
let hasUser = users.length;
if (hasUser) {
console.log('deserialize!')
done(null, users[0]);
} else {
console.log('no user')
done(Error('no user'));
}
});
(I'm not quite sure why your method findOneByAuthId, whose name implies that there will be at most one result, could result in an array)
Also, you're not using the correct convention for passing user data and login errors back to Passport:
if (User.checkPassword(password, hash)) {
done(null, { message: 'success' })
} else {
done(null, { message: 'wrong password' })
}
This should look like this (and obviously, other places where done is called incorrectly should be fixed too):
if (User.checkPassword(password, hash)) {
done(null, user);
} else {
done(null, false, { message: 'wrong password' })
}
(documented here under "Verify Callback")
Finally, you're using passport.authenticate() incorrectly, which is probably the cause of the false being returned. Instead, try this:
router.post('/login', passport.authenticate('local'), (req, res) => {
return res.json(req.user); // or whatever you want to return in case of login success
})
(documented here; if you want to use a custom callback, look for "Custom Callback" on that page)