Cant´t get cookie - Express - express

I created a server with express and have some get/post routes.
In the login page, I have a page that shows the form to login:
app.get("/login", (req, res) => {
res.send(`<h1>Iniciar sesión</h1>
<form method='post' action='/login'>
<input type='email' name='email' placeholder='Email' required />
<input type='password' name='password' placeholder='Contraseña' required />
<input type='submit' value='Ingresar' />
</form>
<a href='/register'>Registrarse</a`);
});
Then I have a Post method in which I set the cookies:
app.post("/login", (req, res) => {
const { email, password } = req.body;
const user = users.filter(
(e) => e.email === email && e.password === password
);
if (user.length >= 1) {
res.cookie("userId", user.id);
res.cookie("password", user.password);
res.redirect("/home");
} else {
console.log("contraseña incorrecta");
res.redirect("/login");
}
});
The problem is that when I go to this route, the user.name and user.email are undefined. In other words, I can´t acces to the cookie:
app.get("/home", (req, res) => {
const id = req.cookies.userId;
console.log(id); //this is undefined
const user = users.filter((u) => u.id === id);
//console.log(user);
res.send(`
<h1>Bienvenido ${user.name}</h1>
<h4>${user.email}</h4>
<a href='/'>Inicio</a>
`);
});
Advices?
Here is the complete code:
const express = require("express");
const morgan = require("morgan");
const cookieparser = require("cookie-parser");
const bodyparser = require("body-parser");
const app = express();
const users = [
{ id: 1, name: "Franco", email: "Franco#mail.com", password: "1234" },
{ id: 2, name: "Toni", email: "Toni#mail.com", password: "1234" },
];
app.use(morgan("dev"));
app.use(cookieparser());
app.use(bodyparser.urlencoded({ extended: true }));
app.use((req, res, next) => {
console.log(req.cookies);
next();
});
app.get("/", (req, res) => {
res.send(`
<h1>Bienvenidos a Henry!</h1>
${
req.cookies.userId
? `<a href='/home'>Perfil</a>
<form method='post' action='/logout'>
<button>Salir</button>
</form>
`
: `
<a href='/login'>Ingresar</a>
<a href='/register'>Registrarse</a>`
}
`);
});
app.get("/register", (req, res) => {
res.send(`<h1>Registrarse</h1>
<form method='post' action='/register'>
<input name='name' placeholder='Nombre' required />
<input type='email' name='email' placeholder='Email' required />
<input type='password' name='password' placeholder='Contraseña' required />
<input type='submit' value='Registrarse' />
</form>
<a href='/login'>Iniciar sesión</a>`);
});
app.get("/login", (req, res) => {
res.send(`<h1>Iniciar sesión</h1>
<form method='post' action='/login'>
<input type='email' name='email' placeholder='Email' required />
<input type='password' name='password' placeholder='Contraseña' required />
<input type='submit' value='Ingresar' />
</form>
<a href='/register'>Registrarse</a`);
});
app.post("/login", (req, res) => {
const { email, password } = req.body;
const user = users.filter(
(e) => e.email === email && e.password === password
);
if (user.length >= 1) {
res.cookie("userId", user.id);
res.cookie("password", user.password);
res.redirect("/home");
} else {
console.log("contraseña incorrecta");
res.redirect("/login");
}
});
app.get("/home", (req, res) => {
const id = req.cookies;
console.log(id);
const user = users.filter((u) => u.id === id);
//console.log(user);
res.send(`
<h1>Bienvenido ${user.name}</h1>
<h4>${user.email}</h4>
<a href='/'>Inicio</a>
`);
});
app.listen(3000, (err) => {
if (err) {
console.log(err);
} else {
console.log("Listening on localhost:3000");
}
});

Part of your problem is that this code:
const user = users.filter(
(e) => e.email === email && e.password === password
);
produces an Array. So, user is an array.
Therefore when you do this:
res.cookie("userId", user.id);
res.cookie("password", user.password);
Both user.id and user.password are ignoring the match you got in user[0] and are referring to non-existent properties on the user array object. They will end up undefined and thus why res.cookie() is not setting a meaningful value.
You should, instead be doing this:
res.cookie("userId", user[0].id);
res.cookie("password", user[0].password);
But, please don't put a password in a user's cookie. There should be no reason to ever do that. Even more so when it's in plain text. If you want to know if the previous user is logged in or not, then use a cryptographically secure token in the cookie (like something express-session uses). Don't put their password in a cookie.

Related

Conditional cookies expiration depends on "Remember me" box, (using passport.js)

I'm a new programmer :)
I'm trying to build an authentication system using passport.js.
Now, I want to determine the expiration of the cookies, depend on "Remember me" checkbox - For the example I chose: if “remember me” cookie expires after 2 minutes, otherwise cookie expires after 1 minute.
The problem is that it doesn't change the cookie's maxAge (it still 1 minute)
my code:
login.hbs
<body class="border border-2 border" style="margin-top: 15%; margin-right: 30%; margin-left: 30%">
<form action="/login" method="POST" class="form-signing container" style="max-width: 30rem">
<div class="text-center">
<!-- <img class="mb-4" src="public/images/wine4u_logo.jpeg" alt="" width="72" height="72"> -->
<h1 class="h3 mb-3 font-weight-normal">Login</h1>
<p>Please Enter your credentials in order to enter our store.</p>
</div>
<hr>
{{#if error}}
<div class="alert alert-danger">{{error}}</div>
{{/if}}
<div class="mb-3 text-left">
<label for="email" class="form-label"><b>Email</b></label>
<input type="email" placeholder="Enter Email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label"><b>Password</b></label>
<input type="password" placeholder="Enter Password" class="form-control" id="password" name="password" required>
</div>
<div class="checkbox mb-3 text-center">
<label>
<input type="checkbox" class="form-label" name="rememberMe" value="remember-me"> Remember me
</label>
<!-- <label for="checkbox"><b>Remember Me?</b></label> -->
<!-- <input type="checkbox" name="rememberMe"> -->
</div>
<div class="text-center">
<button type="submit" class="btn btn-lg btn-primary btn-block">Login</button>
</div>
</form>
<hr>
<form action="/register" class="text-center">
<button type="" class="btn btn-lg btn-secondary btn-block">Sign up page</button>
</form>
<!-- Register -->
</body>
app.js:
if (process.env.NODE_ENV !== "production") {
require("dotenv").config();
}
const express = require("express");
const path = require("path");
const bodyParser = require("body-parser");
const exphbs = require("express-handlebars");
const bcrypt = require("bcrypt");
const passport = require("passport");
const flash = require("express-flash");
const session = require("express-session");
const initializePassport = require("./public/javascript/passport-config");
const methodOverride = require("method-override");
initializePassport(
passport,
(email) => users.find((user) => user.email === email),
(id) => users.find((user) => user.id === id)
);
const app = express();
let users = [];
let cookieLength = 60 * 1000;
// handleBars middleware
app.engine(".hbs", exphbs.engine({ defaultLayout: "main", extname: ".hbs" }));
app.set("view engine", ".hbs");
app.use(bodyParser.json());
app.use(express.urlencoded({ extended: false }));
app.use(flash());
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
rolling: true,
cookie: { maxAge: cookieLength },
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(methodOverride("_method"));
app.get("/", checkAuthenticated, async (req, res) => {
res.render("index", { title: "Welcome to my site" });
});
app.get("/login", checkLoggedIn, async (req, res) => {
res.render("pages/login", {
title: "login page",
noHeader: true,
error: req.flash("error"),
csrf: "CSRF token goes here",
});
});
app.post(
"/login",
checkLoggedIn,
defineCookieLength,
passport.authenticate("local", {
successRedirect: "/",
failureRedirect: "/login",
failureFlash: true,
})
);
app.get("/register", checkLoggedIn, (req, res) => {
res.render("pages/register", { title: "register page", noHeader: true });
});
app.post("/register", async (req, res) => {
try {
const hashedPassword = await bcrypt.hash(req.body.password, 10);
users.push({
id: Date.now().toString(),
username: req.body.name,
email: req.body.email,
password: hashedPassword,
});
console.log("after:", users);
res.redirect("login");
} catch {
res.redirect("/register");
}
});
app.delete("/logout", function (req, res, next) {
req.logout(function (err) {
if (err) {
return next(err);
}
res.redirect("/login");
});
});
app.get("/about", checkAuthenticated, async (req, res) => {
// console.log("users in /login:", users)
res.render("pages/about", { title: "About us" });
});
function defineCookieLength(req, res, next) {
if (req.body.rememberMe === "on") {
req.session.cookie.maxAge = 120 * 1000;
next();
return;
}
next();
}
// validate that the user is already logged in before let him see other pages
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect("/login");
}
// validate that user can't use login/register pages if he is already logged in
function checkLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect("/");
}
next();
}
const PORT = process.env.PORT || 8000;
app.listen(PORT, () => {
console.log(`Server Running on port: http://localhost:${PORT}`);
});
passport-config.js
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
function initialize(passport, getUserByEmail, getUserById) {
const authenticateUser = async (email, password, done) => {
const user = getUserByEmail(email);
if (user == null) {
return done(null, false, { message: "No user with that email" });
}
try {
if (await bcrypt.compare(password, user.password)) {
return done(null, user);
} else {
return done(null, false, { message: "Password incorrect" });
}
} catch (err) {
return done(err);
}
};
passport.use(new LocalStrategy({ usernameField: "email" }, authenticateUser));
passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser((id, done) => {
return done(null, getUserById(id));
});
}
module.exports = initialize;

issues getting data to show on screen from SQL

This is a React Js project that is using Axios, Cors, Express, and Node JS connecting to an SQL database.
I am trying to get the data from an SQL table and have it show on the screen either in a div or p tag each row on its own line. At this time I am able to get it to console.log inside my VS Code terminal from my server.js side as well as console log the data inside my browser console from my frontend of ProductList.js. I do not get any errors in any of my consoles just the data that I would like displayed on the screen.
The below is my server.js
const bodyParser = require('body-parser');
const express = require('express');
cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }))
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/collectors', function (req, res) {
var sql = require("mssql");
const config = {
user: 'XXXXXXX',
password: 'XXXXXXX',
server: 'XXXXXXX',
database: 'XXXXXXX',
options: {
trustServerCertificate: true,
trustedConnection: false,
enableArithAbort: true
},
}
sql.connect(config).then(pool => {
return pool.request()
.query('select * from CollectorAssignment.tCollectors ').then(result => {
console.dir(result)
res.send(result)
})
}).catch(err => {
console.log("error at line24: ", err)
})
sql.on('error', err => {
console.log("error at line28: ", err)
})
});
app.listen(5000, () => {
console.log('listening on port 5000')
});
The below is my ProductList.js
import React from "react";
import axios from 'axios';
class ProductList extends React.Component {
state = {
loading: true,
error: "",
data: []
};
componentDidMount() {
this.getCollectorList();
}
getCollectorList = () => {
this.setState({ loading: true });
return axios
.get(
'http://localhost:5000/collectors'
)
.then(result => {
console.log(result);
this.setState({
CollectorList: result.data.items,
loading: false,
error: false
});
})
.catch(error => {
console.error("error: ", error);
this.setState({
error: `${error}`,
loading: false
});
});
};
render() {
const { loading, error, data } = this.state;
if (loading) {
return <p className="productList">Loading ...</p>;
}
if (error) {
return (
<p className="productList">
There was an error loading the collectors.{" "}
<button onClick={this.loadData}>Try again</button>
</p>
);
}
return (
<div className="productList">
<h1>Collector List</h1>
{data.map(result => <p className="productList">{result.CollectorList}</p>)}
</div>
);
}
}
export default ProductList;
Screenshot of my VS Code console data I get the same info in my browser console which is a total of 16 rows of data that I need displayed on the screen
I have gotten this to start working for me here are the changes I have made to the two files I provided. I was calling a few areas improperly and found that I was looking at some ways for SQL and I am using SQL so some connections to the DB were different which caused some issues small syntax things mainly.
Server.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const config = require('./src/dbfiles/dbConfig')
const app = express();
app.use(cors());
app.use(bodyParser.json({ extended: true }));
var sql = require("mssql");
app.get('/getCollectors', (req, res) => {
sql.connect(config).then(pool => {
return pool.request()
.query('SELECT * FROM CollectorAssignment.tCollectorsTest').then(result => {
res.send(result.recordset)
})
})
})
app.post('/addCollector', function (req, res) {
sql.connect(config).then(pool => {
return pool.request()
.query(`INSERT INTO CollectorAssignment.tCollectorsTest
(
Active,
FirstName,
MiddleInitial,
LastName,
CollectorCode,
CreationDate,
CollectionTeamID
) VALUES (
${req.body.Active},
'${req.body.FirstName}',
'${req.body.MiddleInitial}',
'${req.body.LastName}',
'${req.body.CollectorCode}',
'${req.body.CreationDate}',
1
)`)
.then(result => {
res.send(result)
})
})
});
app.post('/updateCollector', function (req, res) {
sql.connect(config).then(pool => {
return pool.request()
.query(`UPDATE CollectorAssignment.tCollectorsTest
SET ${req.body} = ${req.body}
WHERE ${req.body} = ${req.body}
`)
.then(result => {
res.send(result)
})
})
});
app.delete('/deleteCollector/:CollectorID', (req, res) => {
sql.connect(config).then(pool => {
return pool.request()
.query(`DELETE FROM CollectorAssignment.tCollectorsTest WHERE CollectorID = ${req.params.CollectorID}`).then(result => {
res.send(result.recordset)
})
})
})
app.listen(5000, () => {
console.log('running on port 5000');
})
ProductList.js
import "./userList.css";
import React from "react";
import axios from 'axios';
import { Link } from "react-router-dom";
import { DeleteOutline, Edit } from "#material-ui/icons";
class UserList extends React.Component {
state = {
Collectors: '',
collectorList: []
}
componentDidMount() {
this.getCollectors()
}
getCollectors = () => {
axios.get('http://localhost:5000/getCollectors')
.then((result) => result.data)
.then((result) => {
this.setState({collectorList: result});
});
};
render() {
return (
<div className="userList">
<h3>Collectors</h3>
<table className="blueTableHeaders">
<thead>
<tr>
<th>Active</th>
<td>Collectors</td>
<td>Aging Bucket</td>
<td>Program Code</td>
<td>Finance Company</td>
<td></td>
</tr>
</thead>
</table>
{this.state.collectorList.map((Collectors) => (
<div>
<table className="blueTableData">
<thead>
<tr>
<th><input type="checkbox" name="Active" defaultChecked={Collectors.Active === false ? false : true}/></th>
<td>{Collectors.FirstName} {Collectors.LastName} | {Collectors.CollectorCode}</td>
<td>
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
</td>
<td>
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
</td>
<td>
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
</td>
<td>
<Link to="/updateUser:CollectorID">
<Edit className="editCollector" />
</Link>
<Link to="/deleteUser:CollectorID">
<DeleteOutline className="deleteCollector"/>
</Link>
</td>
</tr>
</thead>
</table>
</div>
))}
<Link to="/newUser">
<button className="userListAddButton">Add Collector</button>
</Link>
<Link to="/deleteUser">
<button className="userListDeleteButton">Delete Collector</button>
</Link>
</div>
);
}
}
export default UserList;

React adding new users to SQL database (undefined entries)

I have been making a website in which I am beginning to create a registration process.I have created the registration form and a server.js file using npm express. However this keeps throwing this error and I'm not sure why.
This is the error
TypeError: Cannot destructure property 'email' of 'req.body' as it is undefined.
All I want to do is so that when submit button is clicked it the users are simply added to the database.
This is the server.js (The error occurs within this file from what I can gather)
const express = require("express");
const sql = require("mssql");
const app = express();
const port = process.env.PORT || 5000;
app.listen(port, () => `Server running on port ${port}`);
const config = {
user: "sas",
password: "Mypassword456",
server: "DEVSQL_2014", // You can use 'localhost\\instance' to connect to named instance
database: "TestDBWebsite"
};
app.post("/admin-Add-Users", function(req, res) {
res.set("Access-Control-Allow-Origin", "*");
const { email, password } = req.body;
let connection = new sql.ConnectionPool(config, function(err) {
let request = new sql.Request(connection);
request.query(
"insert into Login (email, password) values ('" +
password +
"', '" +
email +
"')"
);
});
res.send({ message: "Success" });
});
register.js
import React from "react";
import "../bootstrap.min.css";
import logo from "../codestone logo.png";
import { Link } from "react-router-dom";
import Popup from "reactjs-popup";
import { Formik } from "formik";
import * as Yup from "yup";
function Register() {
return (
<div className="App">
<Header />
<DisplayUsersCS />
</div>
);
}
class DisplayUsersCS extends React.Component {
constructor() {
super();
this.state = { users: [] };
this.onSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
var self = this;
// On submit of the form, send a POST request with the data to the server.
fetch("/admin-Add-Users", {
method: "POST",
body: {
email: self.refs.email,
password: self.refs.password
}
})
.then(function(response) {
return response.json();
})
.then(function(body) {
console.log(body);
});
}
render() {
console.log(this.state.users);
return (
<div>
<LoginForm></LoginForm>
<form onSubmit={this.onSubmit}>
<input type="text" placeholder="email" ref="email" />
<input type="text" placeholder="password" ref="password" />
<input type="submit" />
</form>
</div>
);
}
}
const LoginForm = () => (
<Formik
class="form-signin"
action="auth"
method="POST"
initialValues={{ email: "", password: "", passwordConfirm: "" }}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
console.log("Logging in", values);
setSubmitting(false);
}, 500);
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.email()
.required("Required")
.matches(/(?=.*codestone)/, "This is not a Codestone email address."),
password: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number."),
passwordConfirm: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number.")
})}
>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
handleBlur,
handleSubmit
} = props;
return (
<form
onSubmit={handleSubmit}
class="form-signin"
action="auth"
method="POST"
>
<div className="jumbotron">
<label htmlFor="email">Email</label>
<input
name="email"
type="text"
placeholder="Enter your email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={errors.email && touched.email && "error"}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
<label htmlFor="email">Password</label>
<input
name="password"
type="password"
placeholder="Enter your password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
className={errors.password && touched.password && "error"}
/>
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
<label htmlFor="email">Password Confirmation</label>
<input
name="passwordConfirm"
type="passwordConfirm"
placeholder="Confirm Password"
value={values.passwordConfirm}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.passwordConfirm && touched.passwordConfirm && "error"
}
/>
{errors.passwordConfirm && touched.passwordConfirm && (
<div className="input-feedback">{errors.passwordConfirm}</div>
)}
<button type="submit" action="auth">
Sign Up
</button>
<p>
<Link to="/Login"> Login </Link>
</p>
<p>
<Link to="/reset"> Reset Password </Link>
</p>
</div>
</form>
);
}}
</Formik>
);
function Header() {
return (
<div class="jumbotron">
<img
className="profile-image"
alt="icon"
src={logo}
width="450"
height="80"
/>
</div>
);
}
export default Register;
On client side (react)
To use fetch to post json data, you need to stringify the data in the body
fetch('https://example.com/profile', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((data) => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
On server side (express.js)
You need to include include middleware in order to read the request body. You can refer to the sample codes here https://github.com/expressjs/body-parser

Can not get header token in middleware

When I sign up a user, the header gets set in the /signup route.
Header token set successfully
But when I try to access the header on / route. The authorization fails because in auth.js, getting the header with const token = req.header('curToken') returns undefined. In the network log I can see that the header that has been set (curToken) is empty or non-existent, but is allowed. Can not get Header token
// index.js
const express = require('express')
require('./db/mongoose')
const userRouter = require('./routers/user')
const app = express()
const port = process.env.PORT || 3000
const cors = require('cors')
app.options('*', cors())
app.use(cors())
app.use(express.json())
app.use(userRouter)
app.listen(port, () => {
console.log(`Server is running on port ${port}`)
})
// user.js (express route)
const express = require('express')
const User = require('../models/user')
const auth = require('../middleware/auth')
const router = new express.Router()
// signup
router.post('/signup', async (req, res) => {
const user = new User(req.body)
try {
await user.save()
const token = await user.generateAuthToken()
res.set('curToken', token) // set header
console.log('registered')
res.send({ user, token })
} catch(err) {
res.status(400).send(err)
}
})
// test if token header is accesible
router.get('', auth, async (req, res) => {
try {
// const users = await User.find({})
res.send("logged in.")
} catch(err) {
res.send(err)
}
})
module.exports = router
// auth.js middleware
const jwt = require('jsonwebtoken')
const User = require('../models/user')
const auth = async (req, res, next) => {
res.header('Access-Control-Expose-Headers', 'curToken')
try {
const token = req.header('curToken') // get header
console.log('auth token:', token) // header returns undefined
const decoded = jwt.verify(token, 'thisismysecretcode')
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).send({error: 'Please authenticate.'})
}
}
module.exports = auth
// Sign Up
<template>
<div>
SignUp
<form #submit="sendRegData" #submit.prevent>
<input type="text" v-model="firstName" name="firstName" placeholder="First name"><br>
<input type="text" v-model="lastName" name="lastName" placeholder="Last name"><br>
<input type="text" v-model="email" name="email" placeholder="Email"><br>
<input type="text" v-model="password" name="password" placeholder="Password"><br>
<input type="submit" value="Send">
</form>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "SignUp",
data() {
return {
firstName: null,
lastName: null,
email: null,
password: null
}
},
methods: {
async sendRegData() {
try {
await axios.post('http://localhost:3000/signup', {
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
password: this.password
}).then((res) => {
let token = res.data.token
// console.log('token res received in front:', token)
// localStorage.setItem("currentToken", token)
// console.log('curToken:', localStorage.getItem("currentToken"))
})
} catch(err) {
console.log(err)
}
}
}
};
</script>
// login
<template>
<div class="home">
<!-- <h1>{{ User.firstName }}</h1> -->
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "Page",
data() {
return {
Users: {},
dataFetched: false
}
},
async mounted() {
try {
this.Users = await axios.get('http://localhost:3000/')
console.log(this.Users)
// this.User = this.User.data[0] // transform first object from array
// this.dataFetched = true
} catch(err) {
console.error(err)
}
}
};
</script>

PassportJS Local Endless Loop on Authentication

I'm trying to figure out where the error lies in my authentication code that is creating an endless loop every time I try to login. I think it is within the local strategy passport.use('local', new LocalStrategy section of my code because my console.log(req.body.email); passes back the correct value that was inputted in the field and a query is logged that uses the findOne value, but none of the other console.log are being triggered (one for a email error, another for password error and one for success).
Example: trying to login with test#test.com email address
test#test.com
Executing (default): SELECT `user_id`, `first_name` AS `firstName`, `last_name` AS `lastName`, `email`, `password`, `createdAt`, `updatedAt` FROM `user` AS `user` LIMIT 1;
user.js:
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('user', {
user_id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
firstName: {
type: DataTypes.STRING,
field: 'first_name'
},
lastName: {
type: DataTypes.STRING,
field: 'last_name'
},
email: DataTypes.STRING,
password: DataTypes.STRING,
}, {
freezeTableName: true
});
return User;
}
db-index.js:
var Sequelize = require('sequelize');
var path = require('path');
var config = require(path.resolve(__dirname, '..', '..','./config/config.js'));
var sequelize = new Sequelize(config.database, config.username, config.password, {
host:'localhost',
port:'3306',
dialect: 'mysql'
});
sequelize.authenticate().then(function(err) {
if (!!err) {
console.log('Unable to connect to the database:', err)
} else {
console.log('Connection has been established successfully.')
}
});
var db = {}
db.User = sequelize.import(__dirname + "/user");
db.sequelize = sequelize;
db.Sequelize = Sequelize;
sequelize.sync();
module.exports = db;
site-routes.js:
var express = require('express');
var siteRoutes = express.Router();
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var models = require('../models/db-index');
/*==== Passport Configuration ====*/
// Serialize sessions
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
model.User.find({where: {id: id}}).success(function(user){
done(null, user);
}).error(function(err){
done(err, null);
});
});
passport.use('local', new LocalStrategy({
passReqToCallback : true,
usernameField: 'email'
},
function(req, email, password, done) {
console.log(req.body.email);
//Find user by email
models.User.findOne({ email: req.body.email }, function(err, user) {
//If there is an error, return done
if (err) { return done(err); }
//If user does not exist, log error and redirect
if (!user) {
console.log('No email')
return done(null, false, req.flash('message', 'Email not found.'));
}
//If user exists, but wrong password
if (!user.validPassword(password)) {
console.log('Password fail');
return done(null, false, { message: 'Incorrect password.' });
}
//If all credentials match, return user
console.log('Attempting login');
return done(null, user);
console.log('Successful login');
});
}
));
/*==== Index ====*/
siteRoutes.get('/', function(req, res){
res.render('pages/index.hbs');
});
/*==== Login ====*/
siteRoutes.route('/login')
.get(function(req, res){
res.render('pages/login.hbs');
})
.post(passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/sign-up',
failureFlash: true
}));
siteRoutes.route('/sign-up')
.get(function(req, res){
res.render('pages/sign-up.hbs');
})
.post(function(req, res){
models.User.create({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: req.body.password
}).then(function() {
res.redirect('/');
}).catch(function(error){
res.send(error);
})
});
module.exports = siteRoutes;
login.hbs:
<!DOCTYPE html>
<head>
{{> head}}
</head>
<body>
{{> navigation}}
<div class="container">
<div class="col-md-6 col-md-offset-3">
<form action="/login" method="post">
<label for="login-username">Username</label>
<input type="text" class="form-control" id="login-username" name="email" placeholder="username or email">
<br />
<label for="login-password">Password</label>
<input type="password" class="form-control" id="login-password" name="password">
<div class="login-buttons">
<button type="submit">Login</button>
</div>
</form>
Don't have an account? Then register here!
<br />
Forgot your password?
</div>
</div>
</body>
You are passing a callback function as a second argument to models.User.findOne, but Sequelize functions don't take callbacks. Instead they return a promise. Your code in site-routes.js should look something like this:
passport.use('local', new LocalStrategy({
passReqToCallback: true,
usernameField: 'email'
},
function(req, email, password, done) {
console.log(req.body.email);
//Find user by email
models.User.findOne({
email: req.body.email
})
.then(function(user) {
// handle login here, user will be falsey if no user found with that email
})
.catch(function(err) {
// either findOne threw an exception or it returned a rejected promise
});
}
));
For a full-fledged example of local authentication using passport.js and Sequelize you can see my login-fiddle. Here is a perma-link to the passport local authentication strategy.