How To Make Toast Throw Out Custom Errors - node.js

I am using MongoDB and I installed react toastify to show errors from my backend for sign in but I can not seem to show them. How do I fix this issue? because I can output toast messages but not the custom errors I have.
js file where my toast messages are accessed
const handleSubmit = async (e) => {
e.preventDefault();
try {
const {data} = await axios.post(process.env.REACT_APP_LOGIN, {
username, password
});
if (data.success === true) {
setValues({username: '', password: ''})
toast.success("Sign in successfully");
//save user in local storage
if (typeof window !== "undefined") {
localStorage.setItem("token", JSON.stringify(data));
}
navigate("/map");
}
} catch (err) {
//logs undefined
console.log(`This is the error: ${err.response.data.error}`);
toast.error(`There is an error: ${err.response.data.error}`);
}
}
return (
<div className='loginContainer'>
<div className='logo'></div>
<AddLocationAltIcon/>
Pin
<form className='loginForm'>
<input type='text' className='usernameE' placeholder='username' onChange={handleChange('username')}/>
<input type='password' className='passwordE' placeholder='password' onChange={handleChange('password')} />
<button className='loginBtn' onClick={handleSubmit} type="submit">Login</button>
<button onClick={() => navigate('/register')} className="loginRegister">
Sign Up
</button>
</form>
</div>
)
js file with my custom errors
exports.signin = async (req, res, next)=> {
try {
const {username, password} = req.body;
//if no username and password
if (!username || !password) {
return next(new ErrorResponse(`Username and password are required`, 404))
}
//check username
const user = await User.findOne({username});
if (!user) {
return next(new ErrorResponse(`Invalid credentials`, 404))
}
//verify user password
const isMatched = await user.comparePassword(password);
if (!isMatched) {
return next(new ErrorResponse(`Cannot log in, check your credentials`, 404))
}
generateToken(user, 200, res);
} catch (error) {
console.log(error);
return next(new ErrorResponse(`Cannot log in, check your credentials`, 404))
}
}
ErrorResponse Class
class ErrorResponse extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
module.exports = ErrorResponse;

Related

getting undefined of an array of errors

I am having an issue with my React Redux and Node app. I am trying to Log in an existing user but in my console i am getting the following error:
Uncaught (in promise) TypeError: error.response.data is undefined
The console points to the following block of code:
export const login = (email, password) => async (dispatch) => {
const body = { email, password };
try {
const res = await axios.post('http://localhost:5000/api/auth', body);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(loadUSer());
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: LOGIN_FAIL
});
}
};
This is my server side for user auth auth.js:
const express = require('express');
const router = express.Router();
const User = require('../../models/User');
const auth = require('../../middleware/auth');
const config = require('config');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { check , validationResult } = require('express-validator/');
//#route GET api/auth
//#desc Test route
//#access public
router.get('/',auth, async(req, res)=> {
try{
const user = await User.findById(req.user.id).select('-password');
res.json(user);
}catch(err){
console.error(err.message);
res.status(500).send('Server Error');
}
});
//#route POST api/auth
//#desc Authenticate user & get token
//#access public
router.post('/', [
check('email', 'Plese include a valid email').isEmail(),
check('password', 'Password is required').exists()
],
async (req, res)=> {
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({ errors:errors.array()}); //400 is for bad requests
}
const { email, password } = req.body;
try{
//See if user exists
let user = await User.findOne({ email });
if(!user){
return res.status(400).json({ errors: [{ msg:'Invalid credentials' }] });
}
//Compare the input password, plane text, to the encrypted password.
const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch){
return res.status(400).json({ errors: [{ msg:'Invalid credentials' }] });
}
//Return jsonwebtoken -> this for users to be logged in right after registration
const payload = {
user:{
id: user.id
}
}
jwt.sign(
payload,
config.get('jwtSecret'),
{expiresIn: 360000}, //change to 3600 for production
(err, token)=>{
if(err) throw err;
res.json({ token });
}
)
}catch(err){
console.error(err.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
And this is my Login component:
import React, { Fragment, useState } from 'react'
/* import axios, { Axios } from 'axios'; */
import { Link, Navigate } from 'react-router-dom'
import { connect } from 'react-redux';
import { PropTypes } from 'prop-types';
import { login } from '../../actions/auth';
const Login = ({ login, isAuthenticated }) => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const { email, password } = formData;
const onChange = e => setFormData({
...formData, [e.target.name]:e.target.value
});
const onSubmit = async e => {
e.preventDefault();
login(email, password);
}
//Redirect if logged in
if(isAuthenticated){
return <Navigate to="/dashboard"/>;
}
return (
<Fragment>
<section className='container'>
<h1 className="large text-primary">Sign Up</h1>
<p className="lead"><i className="fas fa-user"></i> Sign Into Your Account</p>
<form className="form" action="create-profile.html" onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input type="email"
placeholder="Email Address"
name="email" value={email}
onChange={e => onChange(e)}
required/>
</div>
<div className="form-group">
<input
type="password"
placeholder="Password"
name="password"
minLength="6"
value={password}
onChange={e => onChange(e)}
required
/>
</div>
<input type="submit" className="btn btn-primary" value="Login" />
</form>
<p className="my-1">
Don´t have an account? <Link to="/register">Sign up</Link>
</p>
</section>
</Fragment>
)
}
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
const mappedStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
})
export default connect(mappedStateToProps , { login })(Login)
For some reason there are sometimes i am able to login and sometimes i encounter this issue but i cannot figure out what am i doing wrong.
My redux devtools also show the AUTH_ERROR action type:
This is my auth.js in my actions directory.
export const loadUSer = () => async dispatch => {
if(localStorage.token){
setAuthToken(localStorage.token);
}
try {
const res = await axios.get('http://localhost:5000/api/auth');
dispatch({
type: USER_LOADED,
payload: res.data
})
} catch (error) {
dispatch({
type:AUTH_ERROR
})
}
}
auth.js (reducers directory):
import{
REGISTER_FAIL,
REGISTER_SUCCESS,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT
} from '../actions/types'
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
loading: true,
user: null
}
function authReducer(state = initialState, action){
const { type, payload } = action
switch (type) {
case USER_LOADED:
return {
...state,
isAuthenticated:true,
loading: false,
user:payload
}
case LOGIN_SUCCESS:
case REGISTER_SUCCESS:
localStorage.setItem('token', payload.token);
return {
...state,
...payload,
isAuthenticated: true,
loading: false
}
case LOGOUT:
case LOGIN_FAIL:
case REGISTER_FAIL:
case AUTH_ERROR:
localStorage.removeItem('token');
return {
...state,
toke: null,
isAuthenticated: false,
loading: false
}
default:
return state;
}
}
export default authReducer
So i first log in with an user everything works fine, i logout and log in with a different user and also works, i now logout and want to login to the first user again and the error shows up. The only difference between both users is that one has a profile and the other one doesn´t.
When i try to log in with the user with no profile my app crashes and my vscode terminal shows a different errors:
Can't set headers after they are sent to the client

Redirect to login page if the user is not authentificated using NextJS and ExpressJS as a backend with axios for binding and MongoDB

i have a problm with this part of the code ,
iam coding a website with NextJS as a frontend and ExpressJS as a backend and MongoDB as a database and i use axios to bind between them so ,
i want to protect the routes from accessing users without login ,
so it must login to acess this routes , if the user try to access to protected route will redirect auto to login page
i try many things to work it up but nothing works ,
i need some help and thanks
this code for App.js for NextJS(front-end)
import '../styles/globals.css'
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import NProgress from 'nprogress'
import '../public/nprogress.css'
function MyApp({ Component, pageProps }) {
const router = useRouter()
useEffect(() => {
const handleStart = (url) => {
console.log(`Loading: ${url}`)
NProgress.start()
}
const handleStop = () => {
NProgress.done()
}
router.events.on('routeChangeStart', handleStart)
router.events.on('routeChangeComplete', handleStop)
router.events.on('routeChangeError', handleStop)
return () => {
router.events.off('routeChangeStart', handleStart)
router.events.off('routeChangeComplete', handleStop)
router.events.off('routeChangeError', handleStop)
}
}, [router])
return(
<>
<Component {...pageProps} />
</>
)}
export default MyApp
and this code for page home that must be protected from not login users , NextJS(front-end)
import Head from "next/head";
import styles from "../styles/Home.module.css";
import NavBar from "./NavBar";
import Footer from "./Footer";
export default function Home() {
return (
<div className={styles.container}>
<Head>
<title>Home</title>
<meta name="description" content="Innovant App" />
<link rel="icon" href="/logo.PNG" />
</Head>
<NavBar />
<div className={styles.body}>
<div className={styles.logohome}>
<div className={styles.logopos}>
<div className={styles.less_symbol}></div>
<div className={styles.grater_symbol}></div>
</div>
</div>
<p className={styles.p}>The Logo Above is Made in Pure CSS</p>
</div>
<Footer />
</div>
);
}
and this code for page login NextJS(front-end)
import Head from 'next/head'
import Image from 'next/image'
import { useRouter } from 'next/router';
import NavBar from './NavBar';
import Footer from './Footer';
import React, { useState } from 'react';
import { Formik } from 'formik'
import axios from 'axios'
import styles from '../styles/SignIn.module.css'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faCheck } from '#fortawesome/free-solid-svg-icons'
import { faUserPlus } from '#fortawesome/free-solid-svg-icons'
import { faSignInAlt } from '#fortawesome/free-solid-svg-icons'
import Link from 'next/link';
const Login = ({ navigation }) => {
const router = useRouter();
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const [message, setMessage] = useState();
const [messageType, setMessageType] = useState();
const url = 'http://192.168.1.9:3001/api/login';
const handleLogin = async (credentials, setSubmitting) => {
handleMessage(null);
axios
.post(url, credentials)
.then(async (response) => {
const result = response.data;
const { status, message, data } = result;
if (status !== 'SUCCESS') {
handleMessage(message, status);
} else {
try {
router.push('/home');
}
catch (error) {
console.log('error to save data')
}
}
setSubmitting(false);
})
.catch((error) => {
setSubmitting(false);
handleMessage('An error occurred. Check your network and try again');
console.log(error);
});
};
const handleMessage = (message, type = '') => {
setMessage(message);
setMessageType(type);
};
return (
<div className={styles.container}>
<Head>
<title>Sign in</title>
<meta name="description" content="innovant App" />
<link rel="icon" href="/logo.PNG" />
</Head>
<div className={styles.nav1}>
<div className={styles.main1}>
<font className={styles.txt2} ><Link href="/" >Sign in</Link></font>
<font className={styles.txt1} ><Link href="/register" >Register</Link></font>
</div>
</div>
<NavBar/>
<form name="formone" >
<div className={styles.body}>
<table className={styles.tab1}>
<tbody>
<tr>
<td>
<div className={styles.verif}>
<FontAwesomeIcon className={styles.facheck} icon={faCheck} />
</div>
</td>
</tr>
<tr>
<td className={styles.td2}>
<Link href={{pathname: '/register',}}>
<FontAwesomeIcon className={styles.iconuser} icon={faUserPlus} /></Link>
<p className={styles.txt4}><Link href={{pathname: '/register',}} >Register</Link></p>
<p className={styles.txt5}>Browse and find what you need</p>
</td>
<td className={styles.td} >
<Link href={{pathname: '/',}}>
<FontAwesomeIcon className={styles.iconuser} icon={faSignInAlt} />
</Link>
<p className={styles.txt4}><Link href={{pathname: '/',}}>Sign in</Link></p>
<p className={styles.txt5}>Already have an account then welcome back</p>
</td>
</tr>
</tbody>
</table>
<Formik
initialValues={{ email: '', password: '' }}
onSubmit={(values, { setSubmitting }) => {
if (email == '' || password == '') {
handleMessage('Please fill in all fields');
setSubmitting(false);
} else {
handleLogin(values, setSubmitting);
}
}}
>
{({ handleChange, handleSubmit, values }) => (
<div className={styles.inputfield}>
<input className={styles.input} type="email" placeholder='Email*' value={values.email} onChange={handleChange('email')} required />
<input className={styles.input} type="password" placeholder='Password*' value={values.password} onChange={handleChange('password')} required />
<p style={{ color: 'red', fontSize: 15, textAlign: 'center' }}>
{message}</p>
<button type="submit" className={styles.btnlogin} onClick={handleSubmit}>
<p className={styles.txt6}>Submit</p>
</button>
</div>
)}
</Formik>
</div>
</form>
<Footer/>
</div>
)
}
export default Login;
and finaly this is the code for API in ExpressJS (Backend)
const express = require("express");
const router = express.Router();
const User = require("./../model/User");
// Password handler
const bcrypt = require("bcrypt");
//register
router.post("/register", (req, res) => {
let { firstname, lastname, email, password, confirmpassword } = req.body;
firstname = firstname;
lastname = lastname;
email = email;
password = password;
confirmpassword = confirmpassword;
if (firstname == "" || lastname == ""|| email == "" || password == "" || confirmpassword == "") {
res.json({
status: "FAILED",
message: "Empty input fields!",
});
} else if (!/^[a-zA-Z ]*$/.test(firstname)) {
res.json({
status: "FAILED",
message: "Invalid firstname entered",
});
}
else if (!/^[a-zA-Z ]*$/.test(lastname)) {
res.json({
status: "FAILED",
message: "Invalid lastname entered",
});
} else if (!/^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$/.test(email)) {
res.json({
status: "FAILED",
message: "Invalid email entered",
});
} else if (password.length < 8) {
res.json({
status: "FAILED",
message: "Password is too short!",
});
} else if (password !== confirmpassword) {
res.json({
status: "FAILED",
message: "sec password must be same!",
});
} else {
// Checking if user already exists
User.find({ email })
.then((result) => {
if (result.length) {
// A user already exists
res.json({
status: "FAILED",
message: "User with the provided email already exists",
});
} else {
// Try to create new user
// password handling
const saltRounds = 10;
bcrypt
.hash(password, saltRounds)
.then((hashedPassword) => {
const newUser = new User({
firstname,
lastname,
email,
password: hashedPassword,
});
newUser
.save()
.then((result) => {
res.json({
status: "SUCCESS",
message: "Signup successful",
data: result,
});
})
.catch((err) => {
res.json({
status: "FAILED",
message: "An error occurred while saving user account!",
});
});
})
.catch((err) => {
res.json({
status: "FAILED",
message: "An error occurred while hashing password!",
});
});
}
})
.catch((err) => {
console.log(err);
res.json({
status: "FAILED",
message: "An error occurred while checking for existing user!",
});
});
}
});
// login
router.post("/login", (req, res) => {
let { email, password } = req.body;
email = email;
password = password;
if (email == "" || password == "") {
res.json({
status: "FAILED",
message: "Empty credentials supplied",
});
} else {
// Check if user exist
User.find({ email })
.then((data) => {
if (data.length) {
// User exists
const hashedPassword = data[0].password;
bcrypt
.compare(password, hashedPassword)
.then((result) => {
if (result) {
// Password match
res.json({
status: "SUCCESS",
message: "Signin successful",
data: data,
});
} else {
res.json({
status: "FAILED",
message: "Invalid password entered!",
});
}
})
.catch((err) => {
res.json({
status: "FAILED",
message: "An error occurred while comparing passwords",
});
});
} else {
res.json({
status: "FAILED",
message: "Invalid credentials entered!",
});
}
})
.catch((err) => {
res.json({
status: "FAILED",
message: "An error occurred while checking for existing user",
});
});
}
});
module.exports = router;
Thanks Again for helping me
For authentication, you must use cookie or HTTP only cookies and JWT.please Read this article you will get more ideas how to handle Authentication in backend and frontend. node-js-express-jwt

How to persist user login in a React & Redux, express backend app with JWT and without packages like redux-persist?

So, here's what I am doing. When the user logs in, the JWT token is set in localStorage. I am trying to persist user login. After logging in, logout button shows on the header but if I refresh, I think the redux store gets cleared up. I read some articles on how to use jwt token verification in react and the /me route or componentDidMount() in App.js itself, but I couldn't understand. Any help would be appreciated.
LoginForm.js
import React, { Component } from "react"
import validator from "validator"
import { loginUser } from "../actions/index"
import { connect } from "react-redux"
class LoginForm extends Component {
constructor(props) {
super(props)
this.state = {
email: "",
password: ""
}
}
handleChange = (event) => {
const { name, value } = event.target
this.setState({
[name]: value
})
}
handleSubmit = (event) => {
event.preventDefault();
const { email, password } = this.state;
const loginData = {
email: this.state.email,
password: this.state.password
}
if (!email || !password) {
return alert('Email and password are must.');
}
if (password.length < 6) {
return alert('Password must contain 6 characters.');
}
if (!validator.isEmail(email)) {
return alert('Invalid email.');
}
this.props.dispatch(loginUser(loginData))
this.props.history.push("/")
}
render() {
const isAuthInProgress = this.props.auth.isAuthInProgress
return (
<div>
<div className="field">
<p className="control has-icons-left has-icons-right">
<input className="input" onChange={this.handleChange} name="email" value={this.state.email} type="email" placeholder="Email" />
<span className="icon is-small is-left">
<i className="fas fa-envelope"></i>
</span>
<span className="icon is-small is-right">
<i className="fas fa-check"></i>
</span>
</p>
</div>
<div className="field">
<p className="control has-icons-left">
<input className="input" onChange={this.handleChange} name="password" value={this.state.password} type="password" placeholder="Password" />
<span className="icon is-small is-left">
<i className="fas fa-lock"></i>
</span>
</p>
<p className="has-text-danger">Forgot password?</p>
</div>
<div className="field">
<p className="control">
{
isAuthInProgress ? <p>Logging in...</p>
:
<button onClick={this.handleSubmit} className="button is-success">
Login
</button>
}
</p>
</div>
</div >
)
}
}
const mapStateToProps = (state) => {
return state
}
export default connect(mapStateToProps)(LoginForm)
actions/index.js
import axios from "axios"
export const registerUser = (registrationData) => {
console.log("inside register action")
return async dispatch => {
dispatch({ type: "REGISTRATION_STARTS" })
try {
const res = await axios.post("http://localhost:3000/api/v1/users/register", registrationData)
dispatch({
type: "REGISTRATION_SUCCESS",
data: { user: res.data },
})
} catch (err) {
dispatch({
type: "REGISTRATION_ERROR",
data: { error: "Something went wrong" }
})
}
}
}
export const loginUser = (loginData) => {
console.log("inside login action")
return async dispatch => {
dispatch({ type: "AUTH_STARTS" })
try {
const res = await axios.post("http://localhost:3000/api/v1/users/login", loginData)
dispatch({
type: "AUTH_SUCCESS",
data: { user: res.data }
})
localStorage.setItem("authToken", res.data.token)
} catch (err) {
dispatch({
type: "AUTH_ERROR",
data: { error: "Something went wrong" }
})
}
}
}
routes/users.js
router.post("/register", userController.registerUser)
router.post("/login", userController.loginUser)
router.get("/:userId", userController.getUser)
router.get("/list", userController.listUsers)
userController.js
const User = require("../models/User")
const auth = require("../utils/auth")
const validator = require("validator")
module.exports = {
registerUser: (req, res, next) => {
const { username, email, password } = req.body
User.create(req.body, (err, createdUser) => {
if (err) {
return next(err)
} else if (!username || !email || !password) {
return res.status(400).json({ message: "Username, email and password are must" })
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invaid email" })
} else if (password.length < 6) {
return res.status(400).json({ message: "Password should be of at least 6 characters" })
}
else {
return res.status(200).json({ user: createdUser })
}
})
},
loginUser: (req, res, next) => {
const { email, password } = req.body
if (!email || !password) {
return res.status(400).json({message: "Email and password are must"})
}
User.findOne({ email }, (err, user) => {
if (err) {
return next(err)
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invalid email" })
} else if (!user) {
return res.status(402).json({ error: "User not found" })
} else if (!user.confirmPassword(password)) {
return res.status(402).json({ error: "Incorrect password" })
}
// generate token here
const token = auth.signToken(email)
res.status(200).json({ user, token })
})
},
getUser: (req, res, next) => {
User.findById(req.params.userId, (err, user) => {
if (err) {
return next(err)
} else if (!user) {
return res.status(404).json({ message: "User not found" })
} else {
return res.status(200).json({ user: user })
}
})
},
listUsers: (req, res) => {
User.find({}, (err, users) => {
if (err) {
return res.status(404).json({ error: "No users found" })
} else {
return res.status(200).json({ user: user })
}
})
}
}
utils/auth.js
const jwt = require("jsonwebtoken")
function signToken(payload) {
return jwt.sign(payload, process.env.JWTSECRET)
}
function verifyToken(req, res, next) {
const token = req.headers.Authorization || req.headers.authorization || ""
if (!token) {
return res.status(403).json({ error: "Not authorized"})
}
jwt.verify(token, process.env.JWTSECRET, (err, decoded) => {
if (err) {
return res.status(403).json({ error: "Not authorized" })
}
req.user = decoded
next()
})
}
module.exports = { signToken, verifyToken }
I think the best way would be to use cookies.
Set the cookie in the login route
res.cookie("authToken", auth.signToken(email), {
httpOnly: false,
})
And then on the react side you can use js-cookie package to retrieve it and use in subsequent authenticated requests
import Cookies from 'js-cookie';
class SomeComponent extends Component {
constructor(props) {
super(props)
this.state = {
email: "",
password: "",
cookie: Cookies.get('authToken')
}
}
}

The authentication is working properly but whenever I typed the wrong email address, my server is getting crashed

The server is keep getting crashed whenever i typed the wrong email address, i understood the problem, but can anyone tell me how to solve this.
Problem:Here the authentication is done for password only, if the password is wrong it is giving me the right error which is "Incorrect email or address", but not give this one when i try with wrong email address.
so i need the authentication for the email address also from my understanding this much i summarized.
Logins.js(API)
var oracledb = require('oracledb');
var bcrypt = require('bcrypt');
var jwt = require('jsonwebtoken');
var config = require(__dirname + '../../config.js');
import { Redirect } from 'react-router'
// var redirect = require("express-redirect");
// var express = require("express");
//var passport = require('passport');
//var LocalStrategy = require('passport-local').Strategy;
//var history = require('history');
//import post from './users';
//var cors = require('cors');
// var history = require('browser-history');
// var app = express();
// redirect(app);
// const targetBaseUrl = '/Signup';
function post(req, res, next) {
console.log('oye')
oracledb.getConnection(
config.database,
function(err, connection){
if (err) {
console.log('haha')
return next(err);
// console.log(err);
}
console.log('fuha')
connection.execute(
'select id as "id", ' +
' email as "email", ' +
' password as "password", ' +
' role as "role" ' +
'from jsao_users ' +
'where email = :email',
{
email: req.body.email.toLowerCase()
},
{
outFormat: oracledb.OBJECT
},
function(err, results){
var user;
console.log('huo')
console.log(err)
//console.log(results)
console.log(results.rows[0])
``````````````````````````````````````````````````````````````````````
if (results.rows[0] === undefined) {
console.log('hiiiiiii')
return <Redirect to='/Signup' />
// app.redirect(targetBaseUrl);
// history.push("/Main");
}
``````````````````````````````````````````````````````````````````
// else {connection.release(function(err) {
// console.log('hy')
// if (err) {
// console.log('joker')
// console.error(err.message);
// }
// });
// return next(err);
// // console.log(err);
// }
user = results.rows[0];
//debugger;
console.log(user)
bcrypt.compare(req.body.password,user.password, function(err, pwMatch) {
var payload;
if (err) {
console.log('wrong');
return next(err);
}
/*if (result == true) {
//res.redirect('http://localhost:3000/Main');
//res.end();
}
else {
res.send('Incorrect password');
//res.redirect('/Signin');
//res.end();
}
/*if(req.body.password != user.password){
res.json({success: false, message: 'passwords do not match'});
}*/
/*if(req.body.password == user.password) {
this.props.history.push("/Main");
}*/
if(pwMatch) {
//this.props.history.push("/Main");
console.log("password matched");
}
else {
res.status(401).send({message: 'Invalid email or password.'});
return;
}
payload = {
sub: user.email,
role: user.role
};
res.status(200).json({
user: user,
token: jwt.sign(payload, config.jwtSecretKey, {expiresIn: "60m" }),
});
});
//res.status(404).end();
connection.release(function(err) {
if (err) {
console.error(err.message);
}
});
});
}
);
}
module.exports.post = post;
Signin.js (Front-end)
import React, { Component } from "react";
import { Button, FormGroup, FormControl, ControlLabel } from "react-bootstrap";
import axios from 'axios';
import "./Signin.css";
class Signin extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: ""
};
}
validateForm() {
return this.state.email.length > 0 && this.state.password.length > 0;
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
}
```````````````````````````````````````````````````````````````
handleSubmit = event => {
event.preventDefault();
const user = {
email: this.state.email,
password : this.state.password
};
// API CALL
axios.post(`http://localhost:4000/api/logins`, user)
.then(res => {
console.log(res);
console.log(res.data);
//console.log("successful");
})
//this.props.history.push("/Main");
}
`````````````````````````````````````````````````````````````````````
render() {
return (
<div className="Login">
<form onSubmit={this.handleSubmit}>
<FormGroup controlId="email" bsSize="large">
<ControlLabel>Email</ControlLabel>
<FormControl
autoFocus
type="email"
value={this.state.email}
onChange={this.handleChange}
/>
</FormGroup>
<FormGroup controlId="password" bsSize="large">
<ControlLabel>Password</ControlLabel>
<FormControl
value={this.state.password}
onChange={this.handleChange}
type="password"
/>
</FormGroup>
<Button
block
bsSize="large"
disabled={!this.validateForm()}
type="submit"
>
Login
</Button>
</form>
</div>
);
}
}
export default Signin;
The expected result for the wrong email address is "Invalid email or password"
But instead getting this error:
C:\Users\anura\Desktop\reactApp\eclaims\src\Backend\routes\logins.js:49
bcrypt.compare(req.body.password,user.password, function(err, pwMatch) {
^
TypeError: Cannot read property 'password' of undefined
at C:\Users\anura\Desktop\reactApp\eclaims\src\Backend\routes\logins.js:49:59
at fetchRowsCb (C:\Users\anura\Desktop\reactApp\eclaims\src\Backend\node_modules\oracledb\lib\connection.js:109:7)
[nodemon] app crashed - waiting for file changes before starting...
The app crashed because you didn't throw exception and return immediately when getting user not found err, because the email is invalid, user variable is null, you cannot read property password of null or undefined
if (err) {
connection.release(function(err) {
if (err) {
console.error(err.message);
}
});
// MUST RETURN HERE !!!
//return next(err);
console.log(err);
}
user = results.rows[0];
// user IS NULL HERE, CANNOT READ PROPERTY OF NULL OR UNDERFINED
//debugger;
bcrypt.compare(req.body.password,user.password, function(err, pwMatch) {
In your callback check for empty values when no entry in db found.
function(err, results){
var user;
...
// put check for empty value if no entries found
if (results.length === 0) {
res.status(401).send({message: 'Invalid email or password.'});
} else {
// rest of your code
user = results.rows[0];
//debugger;
bcrypt.compare(req.body.password,user.password, function(err, pwMatch) {
var payload;
}
...
}
}

NodeJS Express password reset in MVC

I am trying to set up a password-reset route inside my node application, which is suppose to send an email to the user with a password reset link.
The issue that I am having is that I keep receiving the error TypeError: cannot read property json of undefined. To my understanding this means that I am not passing the email correctly to my server side code.
I am having troubles locating the exact place of my bug. I've followed this example, however I've changed it to a more of a MVC architecture. Meaning that I've split the Node code into a service and a controller.
Here is my ReactJS code:
class PasswordResetComponent extends Component {
constructor(props){
super(props);
this.state = {
email:'',
showError:false,
messageFromServer:''
}
}
handleChange = name => event => {
this.setState({
[name]: event.target.value
});
}
sendEmail = e => {
e.preventDefault();
if(this.state.email == ' '){
this.setState({
showError: false,
messageFromServer:' ',
});
}else{
(async () => {
const rawResponse = await fetch(process.env.REACT_APP_SERVER_URI + '/user/password-reset', {
method: 'POST',
body: this.state.email
});
const response = await rawResponse.json();
console.log(response)
})();
}
}
render(){
console.log(this.state.email)
const {email, messageFromServer, showError, showNullError} = this.state;
return(
<div className="container-fluid no-gutters page-login">
<div className="row">
<div className="login-wrapper">
<form onSubmit={this.sendEmail} method="POST">
<div className="form-row">
<div className="form-group col-md-12">
<input type="email" name="email" className="form-control" value={email} onChange={this.handleChange('email')} placeholder="Email" required/>
</div>
</div>
<button type="submit" className="btn btn-primary btn-lg btn-block">Send Confirmation</button>
</form>
<Link to="/login"><button className="mt-4 btn btn-info">Back to Login</button></Link>
</div>
</div>
</div>
);
}
}
Inside my React code, I manage to successfully print out the value of this.state.email meaning that it should be passing fine. I also receive a 200 status on the request.
Here is my Service for password reset:
exports.passwordResetService = async function(email,res, req){
try{
User.findOne({
email: email
}).then(user => {
if( user == null){
res.json('email not in db');
}else{
const token = crypto.randomBytes(20).toString('hex');
console.log(token);
user.update({
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 360000,
});
const transporter = nodemailer.createTransport({
service: 'gmx',
host: 'mail.gmx.com',
port: 587,
secure: true,
auth: {
user: `${process.env.EMAIL_ADDRESS}`,
pass: `${process.env.EMAIL_PASSWORD}`,
},
});
const mailOptions = {
from:'testaccount9909#gmx.com',
to: `${user.email}`,
subject: `Password Reset Email Broh'`,
text:
`Please click the following link to reset your account's password:`+
`http://localhost:3003/reset/${token}\n\n`+
`If you simply ignore the link, your password will remain unchanged!`
}
console.log('sending email...');
transporter.sendMail(mailOptions, function(err, response){
if(err){
console.error('there was an error: ', err);
} else {
console.log('here is the resposne:', response);
res.status(200).json('recovery email sent');
}
})
}
}).catch(error =>
console.log(error)
);
}catch(e){
throw Error("And Error occured while resetting the password");
}
}
Here is my Controller for password reset:
exports.passwordReset = async function(req, res, next){
try{
let passwordResetValue = await UserService.passwordResetService(req.body.email);
return res.status(200).json({status:200, data: passwordResetValue, error:"false", message:"Password reset email has been sent!"})
}catch(e){
console.log(e, "Wopsie wopsie email reset error!");
res.status(400);
}
};
The Place where I am getting the error is inside the Service, more specifically:
if( user == null){
res.json('email not in db');
}
Why am I not passing the user email to the NodeJS service?
The reason you're getting cannot read property json of undefined is because res is not available to passwordResetService since you've not passed it from the route callback and since it's not a middleware
Since all that you're doing with passwordResetService is do some validation and send email you can make few changes to your code like:
// Since you want to send the some success message, you can make a promise wrapper
// to return a promise which you can later await to get status or failure
function mailSender(mailOptions) {
return new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, function(err, response){
if(err){
// could just reject(err) instead
reject('there was an error: ', err);
} else {
console.log('here is the resposne:', response);
resolve('recovery email sent');
}
});
});
}
exports.passwordResetService = async function(email){
let mailStatus;
try{
const user = User.findOne({ email });
if (user === null) {
return ({ message: "email not in db" });
}
const token = crypto.randomBytes(20).toString('hex');
console.log(token);
user.update({
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 360000,
});
const transporter = nodemailer.createTransport({
service: 'gmx',
host: 'mail.gmx.com',
port: 587,
secure: true,
auth: {
user: `${process.env.EMAIL_ADDRESS}`,
pass: `${process.env.EMAIL_PASSWORD}`,
},
});
const mailOptions = {
from:'testaccount9909#gmx.com',
to: `${user.email}`,
subject: `Password Reset Email Broh'`,
text:
`Please click the following link to reset your account's password:`+
`http://localhost:3003/reset/${token}\n\n`+
`If you simply ignore the link, your password will remain unchanged!`
}
console.log('sending email...');
// wait for promise to resolve, if promise is rejected, catch block will catch the error
mailStatus = await mailSender(mailOptions);
} catch(e) {
throw Error("And Error occured while resetting the password");
}
return mailStatus;
}

Resources