Hello then i try to create new user i get error "message": "userdb validation failed: email: Path email is required."
cannot find there is a bad code field
controller.js
const { response } = require('express');
let Userdb = require('../model/model');
// create and save new user object
exports.create = (req, res) => {
// validate requast
if (!req.body) {
res.status(400).send({ message: 'Laukas negali būti tusčias!' });
return;
}
// new user
const user = new Userdb({
name: req.body.name,
email: req.body.email,
gender: req.body.gender,
status: req.body.status,
});
// save user to database
user
.save(user)
.then((data) => {
//res.send(data)
res.redirect('/add-user');
})
.catch((err) => {
res.status(500).send({
message: err.message || 'Kuriant kūrimo operaciją įvyko klaida',
});
});
};
// retrieve and ruturn all users
exports.find = (req, res) => {
Userdb.find();
if (req.query.id) {
const id = req.query.id;
Userdb.findById(id)
.then((data) => {
if (!data) {
res.status(404).send({ message: 'Nerastas naudotojas su id' + id });
} else {
res.send(data);
}
})
.catch((err) => {
res.status(500).send({ message: 'Error gaunant naudojo id' + id });
});
} else {
Userdb.find()
.then((user) => {
res.send(user);
})
.catch((err) => {
res
.status(500)
.send({
message:
err.message || 'Gaunant naudotojo informaciją įvyko klaida',
});
});
}
};
// update a new user by id
exports.update = (req, res) => {
if (!req.body) {
return res
.status(400)
.send({ message: 'Atnaujinant duomenis laukai negali būti tušti!' });
}
const id = req.params.id;
Userdb.findByIdAndUpdate(id, req.body, { useFindAndModify: false })
.then((data) => {
if (!data) {
res
.status(404)
.send({
message: `Negalima atnaujinti naudotojo su ${id}.Naudotojas nerastas!`,
});
} else {
res.send(data);
}
})
.catch((err) => {
res.status(500).send({ message: 'Error atnaujinti nepavyko' });
});
};
// Delete a user with user id
exports.delete = (req, res) => {
const id = req.params.id;
Userdb.findByIdAndDelete(id)
.then((data) => {
if (!data) {
res
.status(404)
.send({ message: `Negalima ištrinti su id ${id}. Blogas id` });
} else {
res.send({
message: 'Naudotojas ištrintas!',
});
}
})
.catch((err) => {
res.status(500).send({
message: 'Negalima ištrinti naudotojo su id=' + id,
});
});
};
model.js;
const mongoose = require('mongoose');
let schema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
gender: String,
status: String,
});
const Userdb = mongoose.model('userdb', schema);
module.exports = Userdb;
router.js;
const express = require('express');
const route = express.Router();
const services = require('../services/render');
const controller = require('../controller/controller');
/**
* #description Root Route
* #method GET/
*/
route.get('/', services.homeRoutes);
/**
* #description add users
* #method GET/ add-user
*/
route.get('/add-user', services.add_user);
/**
* #description for update user
* #method GET/ update-user
*/
route.get('/update-user', services.update_user);
// API
route.post('/api/users', controller.create);
route.get('/api/users', controller.find);
route.put('/api/users/:id', controller.update);
route.delete('/api/users/:id', controller.delete);
module.exports = route;
render.js;
const axios = require('axios');
exports.homeRoutes = (req, res) => {
// Make a get request to api users
axios
.get('http://localhost:3000/api/users')
.then(function (response) {
res.render('index', { users: response.data });
})
.catch((err) => {
res.send(err);
});
};
exports.add_user = (req, res) => {
res.render('add_user');
};
exports.update_user = (req, res) => {
res.render('update_user');
};
connection.js;
const mongoose = require('mongoose');
const connectDB = async () => {
try {
//mongoDB connection string
const con = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log(`MongoDB connected: ${con.connection.host}`);
} catch (err) {
console.log(err);
process.exit(1);
}
};
module.exports = connectDB;
server.js;
const express = require('express');
const dotenv = require('dotenv');
const morgan = require('morgan');
const bodyparser = require('body-parser');
const path = require('path');
const connectDB = require('./server/database/connection');
const app = express();
dotenv.config({ path: 'config.env' });
const PORT = process.env.PORT || 8080;
//log requests
app.use(morgan('tiny'));
// mongoDB connection
connectDB();
// parse request to body-parses
app.use(bodyparser.urlencoded({ extended: true }));
//set view engine
app.set('view engine', 'ejs');
//app.set("views",path.resolve(__dirname,"views/ejs"))
//load assets
app.use('/css', express.static(path.resolve(__dirname, 'assets/css')));
app.use('/img', express.static(path.resolve(__dirname, 'assets/img')));
app.use('/js', express.static(path.resolve(__dirname, 'assets/js')));
//css/style.css
//load routes
app.use('/', require('./server/routes/router'));
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
add this middleware app.use(bodyParser.json());
upper of app.use(bodyparser.urlencoded({extended:true}))
to get data from front
Related
I am getting Error: next is not defined. I don't know in which file I am getting this error.
Code:
server.js
require("dotenv").config({
path: "C:/Users/dogra/Documents/Web Development/Portfolio/FullStack/AdvanceAuth/.env",
});
const express = require("express");
const connectDB = require("./config/db");
const errorHandler = require("./middleware/errorHandler");
connectDB();
const app = express();
app.use(express.json());
app.use("/api/auth", require("./routes/authRoutes"));
app.use("/api/private", require("./routes/privateRoutes"));
app.use(errorHandler);
const PORT = process.env.PORT || 5000;
const server = app.listen(PORT, () => {
console.log(`Server running on PORT: ${PORT}`);
});
process.on("unhandledRejection", (err, promise) => {
console.log(`Logged Error: ${err.message}`);
server.close(() => process.exit(1));
});
controllers
authController.js
const User = require("../models/userModel");
const ErrorResponse = require("../utils/errorResponse");
exports.register = async (req, res, next) => {
const { username, email, password } = req.body;
try {
const user = await User.create({
username,
email,
password,
});
sendToken(user, 201, res);
} catch (error) {
next(error);
}
};
exports.login = async (req, res, next) => {
const { email, password } = req.body;
if (!email || !password) {
return next(new ErrorResponse("Please enter credentials properly", 400));
}
try {
const user = await User.findOne({ email }).select("+password");
if (!user) {
return next(new ErrorResponse("Email not registered", 401));
}
const isMatch = await user.matchPasswords(password);
if (!isMatch) {
return next(new ErrorResponse("Invalid Password", 401));
}
sendToken(user, 200, res);
} catch (error) {
next();
}
};
exports.forgotPassword = (req, res, next) => {
res.send("ForgotPassword Route");
};
exports.resetPassword = (req, res, next) => {
res.send("ResetPassword Route");
};
const sendToken = (user, statusCode, res) => {
const token = user.getSignedJwtToken();
res.status(statusCode).json({ success: true, token });
};
privateController.js
exports.private = (req, res, next) => {
res.status(200).json({
success: true,
data: "You got access to the private data in this route",
});
};
routes
authRoutes.js
const express = require("express");
const router = express.Router();
// controllers
const {
register,
login,
forgotPassword,
resetPassword,
} = require("../controllers/authControllers");
router.route("/register").post(register);
router.route("/login").post(login);
router.route("/forgotPassword").post(forgotPassword);
router.route("/resetPassword/:resetToken").put(resetPassword);
module.exports = router;
privateRoutes.js
const express = require("express");
const router = express.Router();
const { private } = require("../controllers/privateControllers");
const { protect } = require("../middleware/authMiddleware");
router.route("/").get(protect, private);
module.exports = router;
middlewre
authMiddleware.js
const jwt = require("jsonwebtoken");
const User = require("../models/userModel");
const ErrorResponse = require("../utils/errorResponse");
exports.protect = async (req, res, next) => {
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
token = req.headers.authorization.split(" ")[1];
}
if (!token) {
return next(
new ErrorResponse("Not authorized to access to this route", 401)
);
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findById(decoded.id);
if (!user) {
return next(new ErrorResponse("No User found with this id", 404));
}
req.user = user;
next();
} catch (error) {
return next(new ErrorResponse("Not Authorized to access this route", 401));
}
};
errorHandler.js
const ErrorResponse = require("../utils/errorResponse");
const errorHandler = (err, req, res, next) => {
let error = { ...err };
error.message = err.message;
if (err.code === 11000) {
const message = `Duplicate Field value entered`;
error = new ErrorResponse(message, 400);
}
if (err.name === "ValidationError") {
const message = Object.values(err.errors).map((val) => val.message);
error = new ErrorResponse(message, 400);
}
console.log(error.message);
res.status(error.statusCode || 500).json({
success: false,
error: error.message || "Server Error",
});
};
module.exports = errorHandler;
utils
errorResponse.js
class ErrorResponse extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
module.exports = ErrorResponse;
models
userModel.js
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: [true, "Please enter your username"],
},
email: {
type: String,
required: [true, "Please enter your email"],
unique: true,
lowercase: true,
match: [
/^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
,
"Please provide a valid email",
],
},
password: {
type: String,
required: [true, "Please enter a valid password"],
minlength: 8,
select: false,
},
resetPasswordToken: String,
resetPasswordExpired: Date,
});
// Hashing Password
UserSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
});
// Checking if password entered is correct or not
UserSchema.methods.matchPasswords = async function (password) {
return await bcrypt.compare(password, this.password);
};
// Converting user data into JSON WEB TOKEN
UserSchema.methods.getSignedJwtToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRE,
});
};
const User = mongoose.model("User", UserSchema);
module.exports = User;
Sorry, for the long question but I really don't know where is the problem. I googled, & found we get next is not defined error when you don't define it source. But, I have defined it inside my all controllers & middleware's.
The problem was in my dotenv path in server.js Since I cloned my project from GitHub in my new laptop the path was different & I forgot to update the path.
i'm fairly new to express js i want to do a login app so far i did the register part but in login app i want to do the comparaison between the password in database and the password provided by the user and compare it with bcrypt since i'm using it to crypt password , but its not doing the comparaison , what i'm missing here
router
const express = require('express')
const router = express.Router()
const bcrypt = require('bcrypt');
const User = require('../models/user')
const jwt = require('jsonwebtoken')
router.get('/login', function (req, res) {
res.render('login')
})
router.get('/', function (req, res) {
res.render('home')
})
router.get('/register', function (req, res) {
res.render('register')
})
router.post('/register', async function(req,res){
User.beforeCreate((user, options) => {
return bcrypt.hash(user.password, 10)
.then(hash => {
user.password = hash;
})
.catch(err => {
throw new Error();
});
});
return User.create({
username: req.body.name,
password: req.body.password,
email: req.body.email,
createdAt: Date.now()
}).then(function (users) {
res.send(users);
}).catch((err)=>{
console.log(err)
})
})
router.post('/login', function(req,res){
User.findOne({
where:{
username:req.body.name
}
})
.then(user=>{
if(user){
if(bcrypt.compareSync(req.body.password,user.password)){
let token = jwt.sign(user.dataValues,secretKey,{
expiresIn:1440
})
res.send(token)
}
else {
res.status(400).json({
error:'error exissts'
})
}
}
})
.catch(err=>{
res.status(400).json({err:err})
})
})
module.exports = router
models
const sequelize = require('../database/db.js')
const Sequelize = require('sequelize');
const User = sequelize.define('authentication',{
username: {
type: Sequelize.STRING,
allowNull: false
},
password: {
type: Sequelize.STRING
// allowNull defaults to true
} ,
email: {
type: Sequelize.STRING
// allowNull defaults to true
},
created_at: {
field: 'createdAt',
type: Sequelize.DATE,
},
updated_at: {
field: 'updatedAt',
type: Sequelize.DATE,
},
}, {
freezeTableName: true
},
{
notNull: { args: true, msg: "You must enter a name" }
},
)
module.exports = User
index
const express = require('express');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const path = require('path');
// const passport = require('passport');
// const passportJWT = require('passport-jwt');
// Database
const db = require('./database/db');
// Test DB
db.authenticate()
.then(() => console.log('Database connected...'))
.catch(err => console.log('Error: ' + err))
const app = express();
// Handlebars
app.engine('handlebars', exphbs({ defaultLayout: 'main' }));
app.set('view engine', 'handlebars');
// Body Parser
app.use(bodyParser.urlencoded({ extended: false }));
// Set static folder
app.use(express.static(path.join(__dirname, 'public')));
// Importing files
const routes = require("./routes/route");
app.use("/", routes);
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server started on port ${PORT}`));
index.js
const express = require('express');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const path = require('path');
// const passport = require('passport');
// const passportJWT = require('passport-jwt');
// Database
const db = require('./database/db');
// Test DB
db.authenticate()
.then(() => console.log('Database connected...'))
.catch(err => console.log('Error: ' + err))
const app = express();
// Handlebars
app.engine('handlebars', exphbs({ defaultLayout: 'main' }));
app.set('view engine', 'handlebars');
// Body Parser
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
// Set static folder
app.use(express.static(path.join(__dirname, 'public')));
// Importing files
const routes = require("./routes/route");
app.use("/", routes);
const PORT = process.env.PORT || 4500;
app.listen(PORT, console.log(`Server started on port ${PORT}`));
route.js
const express = require('express')
const router = express.Router()
const bcrypt = require('bcrypt');
const User = require('../models/user')
const jwt = require('jsonwebtoken')
const uuid = require('uuidv4').default;
const secretKey = '321'
router.get('/login', function (req, res) {
res.render('login')
})
router.get('/', function (req, res) {
res.render('home')
})
router.get('/register', function (req, res) {
res.render('register')
})
router.post('/register', function(req,res){
User.beforeCreate((user, options) => {
return bcrypt.hash(user.password, 10)
.then(hash => {
user.password = hash;
})
.catch(err => {
throw new Error();
});
});
return User.create({
id: uuid(),
username: req.body.name,
password: req.body.password,
email: req.body.email,
createdAt: Date.now()
}).then(function (users) {
res.send(users);
}).catch((err)=>{
console.log(err)
})
})
router.post('/login', function(req,res){
User.findOne({
where:{
username:req.body.name
}
})
.then(user=>{
if(user){
if(bcrypt.compareSync(req.body.password,user.password)){
let token = jwt.sign(user.dataValues,secretKey,{
expiresIn:1440
})
res.send(token)
}
else {
res.status(400).json({
error:'error exissts'
})
}
}
})
.catch(err=>{
res.status(400).json({err:err})
})
})
module.exports = router
just add app.use(bodyParser.json()) in index.js and define secretKey also add id in user model for primary key and the code working properly
I have been browsing the forum but I am unable to find the error in my code , it always results in false and I am not able to solve it , Please help me...
Is there any other way to authenticate user instead of passport so that I can use it.I am adding more sentences as it is not allowing me to post my query,Sorry..
const http = require("http"),
hostname = "127.0.0.1",
port = 3000,
bodyParser = require("body-parser"),
mongoose = require("mongoose"),
express = require("express"),
passport = require("passport"),
localStrategy = require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose"),
User = require("./models/user");
app = express();
mongoose.connect("mongodb://localhost/drive", { useNewUrlParser: true });
app.set("view engine", "ejs");
app.use(express.static("public"));
app.use(passport.initialize());
app.use(passport.session());
app.use(
require("express-session")({
secret: "Beta tumse na ho payega",
resave: false,
saveUninitialized: false
})
);
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(bodyParser.urlencoded({ extended: true }));
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
});
app.get("/", function(req, res) {
res.render("index");
});
app.get("/register", function(req, res) {
res.send("hello");
});
app.get("/login", function(req, res) {
res.render("login");
});
app.post(
"/login",
passport.authenticate("local", {
successRedirect: "/",
failureRedirect: "/login"
}),
function(req, res) {}
);
app.get("/logout", function(req, res) {
req.logout();
res.redirect("/");
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
console.log("Not logged");
res.redirect("/login");
}
}
app.get("/secret", isLoggedIn, function(req, res) {
res.send("You are logged in");
});
app.post("/register", function(req, res) {
if (req.body.password === req.body.cpassword) {
User.register(
new User({ username: req.body.username }),
req.body.password,
function(err, user) {
if (err) console.log(err);
else
passport.authenticate("local")(req, res, function() {
res.send("signed up");
});
}
);
} else res.send("Password Mismatch");
});
//DRIVE SCHEMA
//var driveSchema = mongoose.Schema({
// title: String,
// created: { type: Date, default: Date.now }
//});
app.listen(port, hostname, function() {
console.log("Server is running at " + hostname + "/" + port);
});
//./models/user.js file
const mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = new mongoose.Schema({
username: String,
password: String
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
I have used passport and jwt library, to authenticate and maintain session for the user. There is no need to maintain user session on server side.
apis/apis.js : This file has all apis end points. /login url will authenticate user using passport and send a token to the client using jwt
const passport = require('passport')
const expRoute = require('express').Router();
let exporter = process.exporter;
expRoute.post('/login', (req, res, next) => {
passport.authenticate(
'local',
{
// successRedirect: '/',
// failureRedirect: '/login',
successFlash: 'Welcome!',
failureFlash: 'Invalid username or password.'
},
(err, user, info) => {
if (err) {
return res.status(500).json(err)
}
else if (user) {
return res.status(200).json({
token: exporter.generateToken(user)
})
}
else {
return res.status(400).json(info)
}
}
)(req, res, next);
})
expRoute.get('/view', exporter.authenticateToken, (req, res) => {
let param = req.finalTokenExtractedData
if (param && exporter.isObjectValid(param, 'tokenId', true, true)) {
let condition = {
_id: param.tokenId
}
let options = {
_id: 0,
password: 0,
__v: 0
}
process.USER.findOne(condition, options) // mongo find
.then((data) => {
res.status(200).json({
result: data,
msg: 'success'
})
})
.catch((mongoErr) => {
exporter.logNow(`USER mongo Error: ${mongoErr}`)
res.status(400).json({
msg: 'user not found'
})
})
}
else {
res.status(404).json({
msg: 'invalid token'
})
}
})
module.exports = expRoute
common/env.js: This file will initialise all connections such mongo, require few files will be used as global
process.CONFIG = require('../configs/config.json')
process.exporter = require("../lib/exporter.js")
process.dbInit = (globalName, mongoUrl, collectionName) => {
require("../models/db-init.js")(mongoUrl, collectionName)
.then((modelObj) => {
process[globalName] = modelObj // will be used as global
})
.catch((dbInitErr) => {
process.exporter.logNow(`dbInit Error: ${dbInitErr}`)
process.exit()
});
}
lib/exporter.js: This file has exporter class which consist of all major functions like mongo connection, authenticateToken, verifyPassword, etc.
const fs = require('fs'),
redis = require("redis"),
path = require("path"),
mongoose = require('mongoose'); mongoose.set('useCreateIndex', true);
const Schema = mongoose.Schema;
var bcrypt = require('bcryptjs')
var jwt = require('jsonwebtoken')
class Exporter {
mongoConnection(mongoURI, schemaObj) {
return new Promise(async (resolve, reject) => {
if (!mongoURI || typeof mongoURI == 'undefined' || mongoURI.length < 1)
return reject('invalid mongo connection url');
return resolve(mongoose.createConnection(mongoURI, { useNewUrlParser: true }))
})
}
createMongoSchema(schemaObj) {
return (new Schema(schemaObj));
}
createMongoModel(mongoDB, collectionName, newSchema) {
if (newSchema)
return mongoDB.model(collectionName, newSchema)
return mongoDB.model(collectionName)
}
authenticateToken(req, res, next) {
const bearerHeader = req.header('authorization')
if (typeof bearerHeader != 'undefined') {
const bearer = bearerHeader.split(' ')
const bearerToken = bearer[1]
jwt.verify(bearerToken, process.CONFIG.jwt.token.activated, (err, data) => {
if (err)
res.status(400).json({
msg: "Invalid token or please try to login again"
})
else {
process.exporter.getSingleHashKeysValuesFromRedis('expired_token', bearerToken)
.then((redisTokendata) => {
if (redisTokendata)
res.status(400).json({
msg: "token expired"
})
else {
req.finalTokenExtractedData = data
// if (req.originalUrl.trim() == process.logoutURL.trim())
req.jwtToken = {
token: bearerToken,
secret: process.CONFIG.jwt.token.activated
}
next()
}
})
.catch((redisTokenError) => {
process.exporter.logNow(`redis token error: ${redisTokenError}`)
res.status(400).json({
msg: "Some went wrong while checking token. Please try later."
})
})
}
})
}
else
res.status(400).json({
msg: "invalid token"
})
}
generateToken(data) {
let expiry = new Date();
// expiry.setDate(expiry.getDate() + 7)
expiry.setMinutes(expiry.getMinutes() + 5)
return jwt.sign({
tokenId: data._id,
exp: parseInt(expiry.getTime() / 1000),
}, process.CONFIG.jwt.token.activated)
}
createPassword(password) {
return new Promise((resolve, reject) => {
if (typeof password == 'undefined' && password == '')
return reject('password empty')
bcrypt.hash(password, 10, async (bErr, hash) => {
if (bErr)
reject(bErr)
else
resolve(hash)
})
})
}
verifyPassword(enteredPassword, savePassword) {
return bcrypt.compareSync(enteredPassword, savePassword)
}
}
module.exports = (new Exporter());
index.js: This is file which you will execute node index.js.
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const passport = require('passport');
require('./common/env')
require('./configs/passport')
const app = express()
const cors = require('cors')
app.use(cors());
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true}))
app.use(passport.initialize())
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
let apis = require('./apis/api')
app.use('/user', apis)
/**
* 404 Handler
*/
app.use((req, res, next)=>{
return res.status(404).send("Endpoint "+req.url +" not found");
})
/**
* if any error or exception occurred then write into a JS file so that app can be restarted
*/
process.on('uncaughtException', (err) => {
console.error(err.stack);
});
app.listen(3000, function(server) {
console.log("App listening at 3000");
});
When index.js file has been executed successfully and listening to a port 3000, then use this URL http://localhost:3000/user/login for authentication, it will accept your username and password, then authenticate using passport and send a token to the client as response. The token can contain user data in encrypted form and have expiry time.
Reference link: https://github.com/arjun-707/login-logout-jwt-nodejs
You need the express-session module.
server.js
// Require a possible config.js file with your configuration variables
const Config = require('./models/config.js');
// If the config module is formed as a class
const config = new Config();
const express = new('express');
const app = express();
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const uuid = require('uuid/v4');
const mongoose = require('mongoose');
// Require your custom passport local strategy file
const passport = require('./models/sessions');
mongoose.connect('mongodb://localhost:27017/your_db_name', {
useNewUrlParser: true
});
// Set the session options
app.use(session({
// Use UUIDs for session IDs
genid: (req) => {
return uuid()
},
// If you want to store the session in MongoDB using mongoose
// Require your personal mon
store: new MongoStore({
mongooseConnection: mongoose.connection
}),
// Define the session secret in env variable or in config file
secret: process.env.SESSION_SECRET || config.sessionSecretKey,
resave: false,
saveUninitialized: true
}));
// Initialize the passport module
app.use(passport.initialize());
// Tell to passport to use session
app.use(passport.session());
./models/session.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt-nodejs');
// Your custom MongoDB connection module
const db = require('./db');
// Configure passport.js to use the local strategy
passport.use(new LocalStrategy({
usernameField: 'username'
},
(username, password, done) => {
db.User.find({
username: username // But it could use email as well
}).then(res => {
const user = JSON.parse(JSON.stringify(res[0]));
if (!user) {
return done(null, false, {
message: 'Invalid credentials.\n'
});
}
if (!bcrypt.compareSync(password, user.password)) {
return done(null, false, {
message: 'Invalid credentials.\n'
});
}
return done(null, user);
}).catch(error => done(error));
}
));
// Tell passport how to serialize the user
passport.serializeUser((user, done) => {
done(null, user._id);
});
// Tell passport how to deserialize the user
passport.deserializeUser((id, done) => {
db.User.find({
_id: id
}).then(res => {
const response = typeof res !== undefined && res.length != 0 ? JSON.parse(JSON.stringify(res[0])) : null;
done(null, response)
}).catch(error => done(error, false))
});
// Export passport for external usage
module.exports = passport;
./models/db.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const uuid = require('uuid/v4');
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/your_db_name', {
useNewUrlParser: true
});
// Define the models container
let models = {};
// Prepare your user schema
const userSchema = Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
// Assign the user schema
models.User = mongoose.model('User', userSchema);
// Export for external usage
module.exports = models;
/*
In that way you can wrap in "models" all schemas:
const newSchema = Schema({
name: String
});
models.Newschema = mongoose.model('Newschema', newSchema);
module.exports = models;
And use it externally like:
const db = require('./models/db');
db.User.find({}).then(docs => {}).catch(err => {});
db.Newschema.find({}).then(docs => {}).catch(err => {});
Etc....
*/
./models/config.js
class Config {
constructor() {
this.sessionSecretKey = "my-awesome-secretkey";
/* And other configurations */
}
}
module.exports = Config;
/*
Externally use like:
const Config = require('./models/config');
const config = new Config();
let sessionSecretKey = config.sessionSecretKey;
*/
Then you can use the req.isAuthenticated() after the login:
// POST the username and password to '/login' router
app.post('/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (info) {
return res.send(info.message)
}
if (err) {
return next(err);
}
if (!user) {
return res.sendStatus(404); // Is a shortcut
// OR -> res.status(404).end();
// OR -> res.status(404).send('Not found'); as you like
}
req.login(user, (err) => {
if (err) return next(err);
// Store the user object retrieved from MongoDB in `req.session`
req.session.user = user;
return res.sendStatus(200); // Is a shortcut
// OR -> res.status(200).end();
// OR -> res.status(200).send('OK'); as you like
})
})(req, res, next);
});
// The logout logic
app.get('/logout', verifySession, function (req, res) {
req.session.destroy(function (err) {
req.logout();
res.redirect('/');
});
});
// Verify the session to protect private routers
function verifySession(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
// Forbidden
res.redirect('/');
// OR -> res.sendStatus(403);
// OR -> res.status(403).end();
// OR -> res.status(403).send('Forbidden'); as you like
}
}
Of course you have to run npm install with all the dependencies required defined in package.json file or manually instal with npm i express-session#latest --s for all the dependencies required: npm i module-name#latest --s.
Don't forget the
const server = app.listen(config.port || 3000, () => {
console.log(`Server running on ${server.address().port} port.`);
});
At the end of server.js file. I hope that it will be useful for you.
I'm running this on Firebase Cloud Functions, soin my index.js,I have the following snippet of code:
const admin = require("firebase-admin");
const functions = require("firebase-functions");
const usersApi = require("./api/users")
const paymentsApi = require("./api/payments")
const express = require('express');
const cors = require('cors');
const app = express();
const checkHeader = async(req, res, next) => {
if(req.headers.authorization) {
admin.auth().verifyIdToken(req.headers.authorization)
.then(token => {
req.uid = token.uid;
req.email = token.email;
req.stripeID = token.stripeID || null;
return next();
})
.catch(e => {
return next(e.errorInfo.code)
})
} else {
return next('No token found');
}
}
app.use(cors({origin: true}));
app.use(express.urlencoded({extended: true}));
app.use(express.json());
//app.use(checkHeader);
app.disable("x-powered-by");
app.use("/users", usersApi)
app.use("/payments", paymentsApi)
exports.api = functions.https.onRequest(app)
and then in my usersApi route:
const express = require('express');
const userRouter = express.Router();
const fb = require('../../fb');
const db = fb.firestore()
userRouter.post('/addUser', (req, res) => {
return db.collection('users').doc(req.uid).set({
activeSub: false,
name: req.body.name
})
.catch(err => {
throw new functions.https.HttpsError('unknown', err.message, {success:false, error: {err}})
})
})
userRouter.post("*", (req, res) => {
res.status(404).send("This route does not exist in userRouter");
})
module.exports = userRouter;
No problems here. I can POST to domain.com/api/users/addUser and I can access that function.
My payments route though doesn't seem to resolve:
const express = require('express');
const paymentRouter = express.Router();
const functions = require("firebase-functions");
const fb = require('../../fb');
const db = fb.firestore()
const stripe = require('stripe')('.....');
paymentRouter.post('/createSubscription'), (req, res) => {
return stripe.subscriptions.create({
customer: req.body.userData.stripeID,
items: [{plan: req.body.plan}]
})
.then((customer) => {
console.log('then')
console.log(customer)
return db.collection('users').doc(req.uid)
.update({
stripeID: customer.id,
activeSub: true
})
})
.catch(e => {
console.log(e)
throw new functions.https.HttpsError('unknown', err.message, e);
})
}
paymentRouter.post('/createUser'), (req, res) => {
console.log('creating user')
return stripe.customers.create({
email: req.email,
source: req.body.token
})
.then(customer => {
console.log(customer)
return db.collection('users').doc(req.uid)
.update({
stripeID: customer.id,
activeSub: true
})
})
.catch(e => {
throw new functions.https.HttpsError('unknown', err.message, e);
})
}
paymentRouter.post("*", (req, res) => {
res.status(404).send("This route does not exist in paymentRouter");
})
module.exports = paymentRouter;
Whenever I send a POST request to domain.com/api/payments/createSubscription or /createUser, it always returns 404 with This route does not exist in paymentRouter"
Can anyone explain why?
Change paymentRouter.post('/createSubscription'), (req, res) => {
to
paymentRouter.post('/createSubscription', (req, res) => {
return stripe.subscriptions.create({
customer: req.body.userData.stripeID,
items: [{plan: req.body.plan}]
})
.then((customer) => {
console.log('then')
console.log(customer)
return db.collection('users').doc(req.uid)
.update({
stripeID: customer.id,
activeSub: true
})
})
.catch(e => {
console.log(e)
throw new functions.https.HttpsError('unknown', err.message, e);
})
}
Change paymentRouter.post('/createUser'), (req, res) => {
paymentRouter.post('/createUser', (req, res) => {
console.log('creating user')
return stripe.customers.create({
email: req.email,
source: req.body.token
})
.then(customer => {
console.log(customer)
return db.collection('users').doc(req.uid)
.update({
stripeID: customer.id,
activeSub: true
})
})
.catch(e => {
throw new functions.https.HttpsError('unknown', err.message, e);
})
}
I am trying to make a small authentication system for a practice project I have. I am trying to send POST requests via postman to my express server(http://localhost:4000/api/register), and it's replying back "404 not found" I am following the tutorial here.
Here is my server.js:
const newpost = require('./routes/newpost');
const getposts = require('./routes/getposts');
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const deleteposts = require('./routes/delete');
const editposts = require('./routes/editposts');
const path = require('path');
const app = express();
const webpack = require('webpack');
const webpackConfig = require('../webpack.config');
const webpackMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const passport = require('passport');
const port = 4000;
const compiler = webpack(webpackConfig);
const config = require('./config/main');
const mongoose = require('mongoose');
const authRouter = require('./routes/authrouter');
const logger = require('morgan');
// db connection
mongoose.connect(config.database);
app.use(passport.initialize());
/*
app.use(webpackMiddleware(compiler, {
noInfo: true, publicPath: webpackConfig.output.publicPath,
}));
app.use(webpackHotMiddleware(compiler, {
log: console.log,
}));
*/
app.use(cors());
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(logger('dev'));
app.use('/newpost', newpost);
app.use('/posts', getposts);
app.use('/delete', deleteposts);
app.use('/edit', editposts);
//auth router to handle auth routes
authRouter(app);
/*
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '../public/index.html'));
}); */
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
Here is my authrouter.js. These are the routes I'm exporting into my server.js. :
const AuthenticationController = require('../controllers/authentication');
const express = require('express');
// const passportService = require('../config/passport');
/* eslint-disable */
const passport = require('passport');
// Middleware to require login/auth
// const requireAuth = passport.authenticate('jwt', { session: false });
const requireLogin = passport.authenticate('local', { session: false });
module.exports = function(app){
"use-strict";
// init route groups
const apiRoutes = express.Router();
const authRoutes = express.Router();
// auth routes
// set auth routes as subgroup/middleware to apiRoutes
apiRoutes.use('/auth', authRoutes);
// Registration routes
authRoutes.post('/register', AuthenticationController.register);
// Login route
authRoutes.post('/login', requireLogin, AuthenticationController.login);
// Set url for API group routes
app.use('/api', apiRoutes);
};
Here is my authentication.js
const jwt = require('jsonwebtoken');
// const crypto = require('crypto'); used for pw resets
const User = require('../models/user');
const config = require('../config/main');
function generateToken(user) {
return jwt.sign(user, config.secret, {
expiresIn: 10080, // in seconds
});
}
// set user info from request
function setUserInfo(request) {
return {
_id: request._id,
email: request.email,
role: request.role,
};
}
// Login Route
exports.login = function (req, res, next) {
const userInfo = setUserInfo(req.user);
res.status(200).json({
token: `JWT${generateToken(userInfo)}`,
user: userinfo,
});
};
// registration route
exports.register = function (req, res, next) {
// check for registration errors
const email = req.body.email;
const password = req.body.password;
// Return error if no email provided
if (!email) {
return res.status(422).send({ error: 'You must enter an email address' });
}
// Return error if no pw provided
if (!password) {
return res.status(422).send({ error: 'You must enter a password' });
}
User.findOne({ email }, (err, existingUser) => {
if (err) { return next(err); }
// if user is not unique, return error
if (existingUser) {
return res.status(422).send({ error: 'That email address is already in use' });
}
// if email is unique and pw was provided, create acct
const user = new User({
email,
password,
});
user.save((err, user) => {
if (err) { return next(err); }
// Subscribe member to Mailchimp list
// mailchimp.subscribeToNewsLetter(user.email);
// Respond with JWT if user was created
const userInfo = setUserInfo(user);
res.status(201).json({
token: `JWT ${generateToken(userInfo)}`,
user: userInfo,
});
});
});
};
// Role authorization check
exports.roleAuthorization = function (role) {
return function (req, res, next) {
const user = req.user;
User.findById(user._id, (err, foundUser) => {
if (err) {
res.status(422).json({ error: 'No user was found' });
return next(err);
}
// if user is found, check role
if (foundUser.role == role) {
return next();
}
res.status(401).json({ error: 'You are not authorized to view this content ' });
return next('Unauthorized');
});
};
};
Here is my passport.js :
// Importing Passport; strategies; and config
const passport = require('passport');
const User = require('../models/user');
const config = require('./main');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const LocalStrategy = require('passport-local');
const localOptions = { usernameField: 'email' };
// setting up the local Strategy
const localLogin = new LocalStrategy(localOptions, ((email, password, done) => {
User.findOne({ email }, (err, user) => {
if (err) { return done(err); }
if (!user) {
return done(null, false, { error: 'Your login details could not be verified. Please try again.',
});
}
user.comparePassword(password, (err, isMatch) => {
if (err) { return done(err); }
if (!isMatch) {
return done(null, false, { error: 'Your login details could not be verified. Please try again.',
});
}
return done(null, user);
});
});
}));
const jwtOptions = {
// Telling passport to check auth headers for JWT
jwtFromRequest: ExtractJwt.fromAuthHeader(),
// Telling passport where to find the secret
secretOrKey: config.secret,
};
// setting up JWT login strategy
const jwtLogin = new JwtStrategy(jwtOptions, ((payload, done) => {
User.findById(payload._id, (err, user) => {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
// allow passport to use the strategies we defined
passport.use(jwtLogin);
passport.use(localLogin);
I believe the correct post endpoint would be api/auth/register