I've been doing some small school project on making our own API and connecting it to an angular front end.
I've been following guide on things and I've came across the problem where my app started throwing internal server error 500 after implementing controllers.
It all worked fine until I've imported the controllers for user registration.
Posts controller works just fine, so does the login part of the ap
I tried logging the errors but it wouldnt output anything.
Here is my code:
user route
const express = require("express");
const UserController = require("../controllers/user");
const router = express.Router();
router.post("/signup", UserController.createUser);
router.post("/login", UserController.userLogin);
module.exports = router;
User controller
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const User = require("../models/user");
exports.createUser = (req, res, next) => {
bcrypt.hash(req.body.password, 10).then(hash => {
const user = new User({
email: req.body.email,
password: hash
});
user
.save()
.then(result => {
res.status(201).json({
message: "User created!",
result: result
});
})
.catch(err => {
res.status(500).json({
message: "Invalid authentication credentials!"
});
});
});
}
exports.userLogin = (req, res, next) => {
let fetchedUser;
User.findOne({ email: req.body.email })
.then(user => {
if (!user) {
return res.status(401).json({
message: "Auth failed"
});
}
fetchedUser = user;
return bcrypt.compare(req.body.password, user.password);
})
.then(result => {
if (!result) {
return res.status(401).json({
message: "Auth failed"
});
}
const token = jwt.sign(
{ email: fetchedUser.email, userId: fetchedUser._id },
"b9SNz3xg9gjY",
{ expiresIn: "1h" }
);
res.status(200).json({
token: token,
expiresIn: 3600,
userId: fetchedUser._id
});
})
.catch(err => {
return res.status(401).json({
message: "Invalid authentication credentials!"
});
});
}
I am expecting to be able to register an account which will be able to post new posts. It all worked just fine until I've made controllers and moved the requests and functions into controller file.
I really apologize for asking this probably simple question, but my programming skills are still low
In userLogin, when the user doesn't exist, you return res.status(401)..., which is chained to the next .then call as result (instead of your expectation that it would be the value returned by bcrypt.compare).
What you can do is instead of:
if (!user) {
return res.status(401).json({
message: "Auth failed"
});
}
try
if (!user) {
throw new Error("Auth failed");
}
which will be caught in your .catch.
Related
I have a auth.js file And a middleware named as fetchuser code given beolow
Can anyone please tell me why am i getting this error.
I am using express js and mongoose but this error is occured during sending token to the user and verify the user whether is user logged in or not.
auth.js
const express = require('express');
const User = require('../models/User');
const router = express.Router();
const { body, validationResult } = require('express-validator');
const bcrypt = require('bcryptjs'); // it is used for password hashing
const jwt = require('jsonwebtoken');
const fetchuser=require('../middleware/fetchuser');
// Route:1 - Create a User using :POST. "/api/auth/createuser". NO Login Required.
router.post('/createuser', [
body('email', 'Enter valid email').isEmail(),
body('name', 'Enter valid email').isLength({ min: 3 }),
body('password').isLength({ min: 5 })
], async (req, res) => {
// Check fo vaidation whether is any rule(defined in User model) breaked or not
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Check Whether user with same email id exist or not
try {
let user = await User.findOne({ email: req.body.email });
if (user) {
return res.status(400).json({ error: "Sorry user with same email id already exist" });
}
// hashing of password
const salt = await bcrypt.genSalt(10);
const securePassword = await bcrypt.hash(req.body.password, salt);
// create A new User
user = await User.create({
name: req.body.name,
email: req.body.email,
password: securePassword
})
// returning user id in Token
const JWT_secret = "Rishiisa#boy";
const data = { user:{id: user.id} };
const auth_token = jwt.sign(data, JWT_secret);
res.json({ auth_token });
}
catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
// Route:2 - Login a User using credential. "/api/auth/login". NO Login Required.
router.post('/login', [
body('email', 'Enter valid email').isEmail(),
body('password', 'password can not be blank').exists(),
], async (req, res) => {
// Check for vaidation according to the rule defined at line no. 53, 54;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// destructure the email and password from body request
const { email, password } = req.body;
try {
// Checking whether email is exist or not
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ error: "Please try to login using correct credentials" });
}
// Now Comparing password with help of bcryptjs
const comparepassword = await bcrypt.compare(password, user.password);
if (!comparepassword) {
return res.status(400).json({ error: "Please try to login using correct credentials" });
}
// Now if user enter coorect password and login then user got logged in;
// And We will send authtoken to user;
// returning user id in Token
const JWT_secret = "Rishiisa#boy";
const data = { user:{id: user.id} };
const auth_token = jwt.sign(data, JWT_secret);
res.json({ auth_token });
}
catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
// Route:3 - Get Loggedin User details using:POST "/api/auth/getuser" Login required
router.post('/getuser', fetchuser, async (req, res) => {
try {
const userid = req.user.id;
const user = await User.findById(userid).select("-password");
res.send(user);
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
module.exports = router
middleware:
fetchuser.js
const jwt = require('jsonwebtoken');
const JWT_secret = "Rishiisa#boy";
const fetchuser = (req, res, next) => {
// Get the user from jwt token and add user id to req object
const token = req.header('auth_token');
if (!token) {
res.status(401).send({ error: "Please authenticate using a valid token" });
}
try {
const data = jwt.verify(token, JWT_secret);
req.user = data.user;
next();
} catch (error) {
res.status(401).send({ error: "Please authenticate using a valid token" });
}
}
module.exports = fetchuser;
In auth.js, where you wrote: "const data = { user:{id: user.id} };" Try changing user.id to user._id, since in MongoDB the user id is referred to as '_id'.
Let me know if that works.
I've had problems sending jwt token back and even verifying it, but all is good on my side now.
Also, below is my (inspired) method of going about this:
router.post('/register', (req, res)=>{
const { username, password } = req.body;
const user = new User({
username,
password
});
bcrypt.genSalt(10, (err, salt)=>{
bcrypt.hash(user.password, salt, (err, hash)=>{
if(err) throw err;
user.password = hash;
user.save()
.then(user=>{
jwt.sign(
{ id: user._id },
process.env.jwtSecret,
{ expiresIn: 3600 },
(err, token) =>{
if(err) throw err;
res.status(200)
}
)
})
})
})
})
I am setting access_token in login route but I am getting undefined.
Lines commented below in the code gives undefined why so? How to access the cookie when it is set ? There is another GET route /transactions which gets called on home page after login is success in that route as well I am getting undefined why so? I have also used cookie-parser in server.js file but still not working
transaction GET route https://pastebin.com/DP0NZL5W
const express = require('express');
const router = express.Router();
const jwt = require('jsonwebtoken');
const User = require('../models/userSchema');
router.post('/login', (req, res) => {
const {email, password} = req.body;
console.log("Server Login email: ", email);
console.log("Server Login password: ", password);
User.find({email: email})
.exec()
.then(user => {
console.log("User login user: ", user);
if(user.length < 1){
console.log("user length less")
return res.status(401).json({
message: 'Auth failed'
});
}
bcrypt.compare(password, user[0].password, (err, result) => {
if(err){
return res.status(401).json({
message: 'Auth failed'
});
}
if(result){
const token = jwt.sign({
email: user[0].email,
userId: user[0]._id
}, 'secret', {
expiresIn: "1h"
})
console.log("Cookie token: ", token);
res.cookie('access_token', token, { maxAge: 9000000, httpOnly: true });
// console.log("req.cookies: ", req.cookies)
// console.log("req.cookies['access_token']: ", req.cookies['access_token'])
return res.status(200).json({
message: 'Auth successful',
token: token
})
}
return res.status(401).json({
message: 'Auth failed'
});
})
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
})
});
app.use({
credentials: true, // enable cookie receiving
origin: "url of client side" // how can use your api
})
I'm trying to get the user to be able to sign up to my website, and store the credentials on mongodb.
This is my auth.js file, where the route is defined:
router.post('/signup', (req,res,next) => {
Passport.authenticate('local-signup', err => {
if (err) {
if (err.name === "MongoError" && err.code === 11000) {
res.status(409).json({
success: false,
message: "Unsuccessful",
errors: {
email: "This email is already taken."
}
});
}
res.status(400).json({
success: false,
message: "Unsuccessful",
errors: {
unknown: "Could not process for some reason. Contact admin."
}
});
}
res.status(200).json({
success: true,
message: "Successful",
errors: {}
});
}) (res, req, next);
}
That last bracket got a bit messed up but believe me, it's not a syntax error.
This snippet is where I have defined the passport strategy:
require ('../Models/Users')
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/onlinestore');
const User = mongoose.model('User');
const PassportLocalStrategy = require('passport-local').Strategy;
const Passport = require('passport');
module.exports = Passport.use(new PassportLocalStrategy({
usernameField: 'email',
passwordField: 'password',
session: false,
passReqToCallback: true,
}, (email, password, done) => {
let user = new User();
user.email = email.trim();
user.password = password.trim();
user.save(err => {
if (err) {
console.log(err);
return done(err);
} else {
console.log("Success");
return done(null);
}
});
}
));
The route is able to get the user inputted password and user. When I click submit, literally nothing happens; the server doesn't console anything nor does the client. After a bit of debugging I think the issue is due to the fact that Passport.Authenticate is not being called but I'm not sure why. I can post other code snippets if necessary, thanks!
This is OP. I was able to find the solution.
1) In my auth.js file,
Passport.authenticate('local-signup', err => {
replace the 'local-signup' with 'local'
so it becomes:
Passport.authenticate('local', err => {
2) I happened to have multiple Passport strategies and each are in their own file, (one for login and one for signup). To use the correct "local" I have to import the correct one in my auth.js file. Easy enough, it's
const passport = require('../Passport/local-signup');
For login, it would be a different file.
I'm trying to verify the user's password using bcrypt. But, unfortunately, my post-request does not work, it just loads for a long time and that's it.
I have a model user.js with this code:
UserSchema.methods.comparePasswords = function (password) {
return bcrypt.compare(password, this.password);
};
And i have a controller auth.js with this code:
export const signin = async (req, res, next) => {
const { login, password } = req.body;
const user = await User.findOne({ login });
if (!user) {
return next({
status: 400,
message: 'User not found'
});
}
try {
const result = await user.comparePasswords(password);
} catch (e) {
return next({
status: 400,
message: 'Bad Credentials'
});
}
req.session.userId = user._id;
req.json(user);
};
The handling of incorrect input works well and the server returns false messages for me, but does not process the correct input.
I have a ReactJS and Redux connected to MongoDB, Mongoose.
I have a Mongoose Schema (user.js) set up like so:
var UserSchema = new Schema({
email: {
type: String,
lowercase: true,
unique: true,
required: true
},
})
And a API controller that receives the email string request, and then if nothing is entered in the text field, it sends a 422 error, and inside User.findOne, if the email already exists in the database, then it throws a 422 error and if not, does user.save to save it in the database.
"use strict";
const User = require('../models/user')
exports.register = function(req, res, next) {
const email = req.body.email;
console.log('ERROR 1')
if(!email) {
return res.status(422).send({ error: 'You must enter an email address.'})
console.log('ERROR 1')
}
User.findOne({ email: email }, function(err, existingUser) {
if(err) { return next(err); }
console.log('ERROR 2')
if(existingUser) {
return res.status(422).send({ error: 'That email address is already in use.'})
}
console.log('ERROR 3')
let user = new User({
email: email,
})
console.log('ERROR 4')
user.save(function(err, user) {
if(err) { return next(err); }
console.log('ERROR 5')
res.status(201).json({
user: user,
})
})
})
console.log('ERROR 6')
}
And I am making a POST request as such:
export function registerUser({ email }) {
return function(dispatch) {
axios.post(`${API_URL}/auth/register`, { email })
.then(response => {
console.log('THIS IS TESTING PURPOSE')
console.log(response)
dispatch({ type: AUTH_USER });
})
.catch((error) => {
errorHandler(dispatch, error.response, AUTH_ERROR)
});
}
}
I made several POST requests and all get successful status back from API with sever config: {'database': 'mongodb://localhost/practicedb',
'port': process.env.PORT || 3000}, yet the data never gets saved and database (practicedb) doesn't show up on Terminal.
Everything seem to be set up correctly but why the problem? Could I be missing something? Any insight or guidance would be really appreciated.
Thank you in advance!
Here are some logs and what's OPTIONS request that I never made:
Tried registering with same email again:
Correct if i'm wrong but your bare save method is not async. Save method return a promise. See http://mongoosejs.com/docs/promises.html
EDIT
user.save().then(function(doc) {
if (!doc) { next(new Error('Error while persisting!')); }
console.log('ERROR 5');
res.status(201).json({
user: doc
});
});
You can also achieve this with any promised library (Q, bluebird) or use ES6 Promise. Alternatively use async.
Example with Q. NOT TESTED:
"use strict";
const User = require('../models/user');
const Q = require('Q'); //add https://github.com/kriskowal/q
exports.register = function(req, res, next) {
const email = req.body.email;
console.log('ERROR 1')
if(!email) {
return res.status(422).send({ error: 'You must enter an email address.'})
console.log('ERROR 1')
}
var deferred = Q.defer();
User.findOne({ email: email }, function(err, existingUser) {
if(err) { return next(err); }
console.log('ERROR 2')
if(existingUser) {
return res.status(422).send({ error: 'That email address is already in use.'})
}
console.log('ERROR 3')
let user = new User({
email: email,
})
console.log('ERROR 4')
user.save(function(err, user) {
if(err) {
deferred.reject(err);
return next(err);
}
console.log('ERROR 5')
deferred.resolve(user); //
});
res.status(201).json({
user: deferred.promise,
})
})
console.log('ERROR 6')
}