I get this error message when I try to test the /api/register end point with Postman and following POST request:
{
"name" : "first",
"email" : "first#one.com",
"password" : "123"
}
[uncaught application error]: TypeError - Cannot read properties of undefined (reading 'name')
request: { url: "http://0.0.0.0:8000/api/register", method: "POST", hasBody: true }
response: { status: 404, type: undefined, hasBody: false, writable: true }
at register (file:///C:/Users/m/app_back/controllers/auth_controller.ts:9:22)
at async dispatch (https://deno.land/x/oak#v9.0.1/middleware.ts:41:7)
at async dispatch (https://deno.land/x/oak#v9.0.1/middleware.ts:41:7)
at async dispatch (https://deno.land/x/oak#v9.0.1/middleware.ts:41:7)
at async EventTarget.#handleRequest (https://deno.land/x/oak#v9.0.1/application.ts:379:9)
TypeError: Cannot read properties of undefined (reading 'name')
at register (file:///C:/Users/m/app_back/controllers/auth_controller.ts:9:22)
at async dispatch (https://deno.land/x/oak#v9.0.1/middleware.ts:41:7)
at async dispatch (https://deno.land/x/oak#v9.0.1/middleware.ts:41:7)
at async dispatch (https://deno.land/x/oak#v9.0.1/middleware.ts:41:7)
at async EventTarget.#handleRequest (https://deno.land/x/oak#v9.0.1/application.ts:379:9)
This is my auth_controller.ts file:
import {
create, verify, decode, getNumericDate, RouterContext, hashSync, compareSync
} from "../deps.ts";
import { userCollection } from "../mongo.ts";
import User from "../models/user.ts";
export class AuthController {
async register(ctx: RouterContext) {
const { value: { name, email, password } } = await ctx.request.body().value;
let user = await User.findOne({ email });
if (user) {
ctx.response.status = 422;
ctx.response.body = { message: "Email is already used" };
return;
}
const hashedPassword = hashSync(password);
user = new User({ name, email, password: hashedPassword });
await user.save();
ctx.response.status = 201;
ctx.response.body = {
id: user.id,
name: user.name,
email: user.email
};
}
async login(ctx: RouterContext) {
const { value: { email, password } } = await ctx.request.body().value;
if (!email || !password) {
ctx.response.status = 422;
ctx.response.body = { message: "Please provide email and password" };
return;
}
let user = await User.findOne({ email });
if (!user) {
ctx.response.status = 422;
ctx.response.body = { message: "Incorrect email" };
return;
}
if (!compareSync(password, user.password)) {
ctx.response.status = 422;
ctx.response.body = { message: "Incorrect password" };
return;
}
const key = await crypto.subtle.generateKey(
{ name: "HMAC", hash: "SHA-512" },
true,
["sign", "verify"],
);
const jwt = create( {
alg: "HS256",
typ: "JWT",
}, {
iss: user.email,
exp: getNumericDate(
Date.now() + parseInt(Deno.env.get("JWT_EXP_DURATION") || "0"))
},
key
);
ctx.response.body = {
id: user.id,
name: user.name,
email: user.email,
jwt,
};
}
}
export default new AuthController();
What is the problem and how can I resolve it?
EDIT: I added this line to the code:
console.log( await ctx.request.body().value );
And this is the result:
{ name: "first", email: "first#one.com", password: "123" }
You are facing this issue because you are trying to access ctx.request.body().value.value.name (notice multiple value porperties). You could change line 9 of your auth_controller.ts to this to fix it:
const { name, email, password } = await ctx.request.body().value;
On a side note, I also noticed few more issues with your current code.
Your JWT algorithm and generated secret key encryption algorithm should match
So either change your hash encryption on line 47 to SHA-256 or your JWT algorithm on line 53 to HS512.
You don't need to pass current date to getNumericDate function
This helper function already does this job for you, all you need to pass here is the time period (in seconds) when you want your token to expire. In your case it would be:
getNumericDate(Deno.env.get("JWT_EXP_DURATION") || 0)}
So I'm having trouble authenticating a user login using express for the backend. If I do a simple res.send I could get a response in postman. but if I do a check if the user and password check and generate a token if says error 401 invalid usernames and password. mind the tokens work for register and update profiles. I also attached the user schema.
Simple Approach
const authUser = asyncHandler(async (req, res) => {
const { email, password } = req.body
res.send({ email, password })
})
When I try to check and generate a token
const authUser = asyncHandler(async (req, res) => {
const { email, password } = req.body
const user = await User.findOne({ email })
if (user && (await user.matchPassword(password))) {
res.json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user._id),
})
} else {
res.status(401)
throw new Error('Invalid Email or password')
}
})
Also here's my user schema using mongoose and added a function to check password since in the database it's encrypted using bcrypt.js
import mongoose from 'mongoose'
import bcrypt from 'bcryptjs'
const userSchema = mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
isAdmin: {
type: Boolean,
required: true,
default: false,
},
},
{
timestamps: true,
}
)
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password)
}
const User = mongoose.model('User', userSchema)
export default User
You see, your code is absolutely correct, but only if you have saved the user correctly in your model at the first. In addition, the password used during storage is hashed in the same way and from the same module.
Now you have to change your checking terms because there may not really be a user with this email in the database to match your password and return true value.
import mongoose from 'mongoose'
import bcrypt from 'bcryptjs'
const userSchema = mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
isAdmin: {
type: Boolean,
required: true,
default: false,
},
},
{
timestamps: true,
}
)
userSchema.pre('save', function (next) {
if (this.password) {
bcrypt.hash(this.password, bcrypt.genSaltSync(15), (err, hash) => {
if (err) console.log(err);
this.password = hash;
next();
});
}
}
userSchema.methods.Save = async (data) => {
let model=new User(data)
await model.save();
}
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password)
}
const User = mongoose.model('User', userSchema)
export default User
and update this code:
const authUser = asyncHandler(async (req, res) => {
const { email, password } = req.body
const user = await User.findOne({ email })
if (user) {
if(await user.matchPassword(password)) {
res.json({
_id: user._id,
name: user.name,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user._id),
})
} else {
res.status(401)
throw new Error('Invalid password')
}
} else {
res.status(401)
throw new Error('Invalid Email')
}
})
Now you know which part of the job is the problem. No user or no wrist password
I am implementing a reset password feature on for the users of my website. However, it seems to throw this error when the user confirms new password at the reset.ejs page.
The following steps are being performed correctly:
Token sent on mail
When clicked on token, new password page opens
When user enters new password and confirm new password and hits the button to save the new password, the function in users.js user.setPassword does not work as the error is mentioned below. It is a built in function of passport-local-mongoose.
ERROR: user.savePassword is not a function
Including all the code files below:
users.js:
var express = require('express');
var router = express.Router();
var multer = require('multer');
var upload = multer({dest: './uploads'});
var passport = require('passport');
var mongoose = require('mongoose');
var LocalStrategy = require('passport-local').Strategy;
var randomstring = require("randomstring");
var User = require('../models/user');
var data=require('../models/data');
var checklist=require("../models/checklist");
var async = require("async");
var crypto = require("crypto");
var passportLocalMongoose=require("passport-local-mongoose");
// "use strict";
const nodemailer = require("nodemailer");
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.get('/register/:type', function(req, res, next) {
res.render('user/register.ejs',{title:'Register',type:req.params.type});
});
router.get('/login', function(req, res, next) {
res.render('user/login.ejs', {title:'Login'});
});
router.post('/login',
passport.authenticate('local',{failureRedirect:'/users/login', failureFlash: 'Invalid username or password'}),
function(req, res) {
var previouspath=req.cookies.previouspath;
if(req.cookies.checklist==undefined){
req.flash('success', 'You are now logged in');
if(req.user.as=='seller'){
if(previouspath!=undefined){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer');
}
else
res.redirect('/buyer');
}
else {
if(previouspath!=undefined){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer');
}
else
res.redirect('/buyer');
}
}
else{
var ids=req.cookies.checklist['data']
var checks=[];
for(var i=0;i<ids.length;i++){
checks.push({user:req.user,data:ids[i]});
}
checklist.insertMany(checks,function(err, d) {
if(err)console.log(err);
res.clearCookie('checklist');
req.flash('success', 'You are now logged in');
if(req.user.as=='seller'){
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/seller')
}
else {
if(previouspath.length!=0)
res.redirect(previouspath);
else
res.redirect('/buyer')
}
});
}
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(function(username, password, done){
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) return done(err);
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message:'Invalid Password'});
}
});
});
}));
router.post('/register/:type',function(req, res, next) {
var name = req.body.name;
var email = req.body.email;
var username = req.body.username;
var institution=req.body.institution;
var education=req.body.education;
var proffession=req.body.proffession;
var country=req.body.country;
//check if email does not already exists
//check if username does not already exists
User.find({ $or: [ { email: { $eq: req.body.email } }, { username: { $eq: req.body.username } } ] },function(err,data){
if(err)console.log(err);
if(data.length!=0){
console.log(data.length);
req.flash('success','email or username is repeated.');
res.redirect('/users/register/'+req.params.type);
}
else
{
var password = req.body.password;
var password2 = req.body.password2;
var as =req.params.type;
// Form Validator
req.checkBody('name','Name field is required').notEmpty();
req.checkBody('email','Email field is required').notEmpty();
req.checkBody('email','Email is not valid').isEmail();
req.checkBody('username','Username field is required').notEmpty();
req.checkBody('password','Password field is required').notEmpty();
// Check Errors
var errors = req.validationErrors();
if(errors){
res.render('user/register.ejs', {
errors: errors
});
} else{
var newUser = new User({
name: name,
email: email,
username: username,
password: password,
as :as,
institution:institution,
education:education,
proffession:proffession,
country:country
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
// res.location('/');
var token=randomstring.generate(7);
var to=req.body.email;
var subject='Email Confirmation from dataSeed ';
var message='<h1>Use this code to register </h1><p>Your verification Code is: <h2>'+token+'</h2></p>';
var mailOptions=sendmail(to,subject,message);
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
}
else
{
res.render('user/emailconfirmation.ejs',{username:req.body.username,token:token});
}
});
}
}
});
function sendmail(to,subject,message){
var mailOptions = {
from: 'dataseedltd#gmail.com',
to: to,
subject: subject,
html: message
};
return mailOptions;
}
router.post('/emailconfirmation/:token',function(req, res) {
if(req.params.token==req.body.token){
req.flash('success', 'You are now registered and can login');
res.redirect('/');
}
else{
User.remove({username:req.body.username},function(err,data){
if(err)console.log(err);
res.redirect('/');
});
}
});
});
router.get('/logout', function(req, res){
req.logout();
req.flash('success', 'You are now logged out');
res.redirect('/users/login');
});
//Forgot Password
router.get('/forgot',function(req,res){
res.render("forgotpassword.ejs");
});
router.post('/forgot', function(req, res, next) {
async.waterfall([
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('success', 'No account with that email address exists.');
return res.redirect('/users/forgot');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
var mailOptions = {
to: user.email,
from: 'dataseedltd#gmail.com',
subject: 'Node.js Password Reset',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/users/reset/' + token + '\n\n' +
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
console.log('mail sent');
req.flash('success', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
});
}
], function(err) {
if (err) return next(err);
res.redirect('/users/forgot');
});
});
router.get('/reset/:token', function(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('success', 'Password reset token is invalid or has expired.');
return res.redirect('/users/forgot');
}
res.render('reset', {token: req.params.token});
});
});
router.post('/reset/:token', function(req, res) {
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
}
if(req.body.password === req.body.confirm) {
user.setPassword(req.body.password, function(err) {
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
})
} else {
req.flash("error", "Passwords do not match.");
return res.redirect('back');
}
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'dataseedltd#gmail.com',
pass: 'mypassword'
}
});
var mailOptions = {
to: user.email,
from: 'dataseedltd#gmail.com',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
req.flash('success', 'Success! Your password has been changed.');
done(err);
});
}
], function(err) {
res.redirect('/login');
});
});
module.exports = router;
users.js (model):
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var passportLocalMongoose=require("passport-local-mongoose");
mongoose.connect('mongodb://localhost/dataseed');
var db = mongoose.connection;
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
profileimage:{
type: String
},
as:{
type:String
},
institution:{
type:String
},
education:{
type:String
},
proffession:{
type:String
},
country:{
type:String
},
resetPasswordToken: String,
resetPasswordExpires: Date
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
callback(null, isMatch);
});
}
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
It seems like you don't have a method called setPassword defined under user model. This is mainly because you haven't plugin the passport-local-mongoose to UserSchema. Add UserSchema.plugin(passportLocalMongoose); before creating the model from UserSchema. like this
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var passportLocalMongoose=require("passport-local-mongoose");
mongoose.connect('mongodb://localhost/dataseed');
var db = mongoose.connection;
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
profileimage:{
type: String
},
as:{
type:String
},
institution:{
type:String
},
education:{
type:String
},
proffession:{
type:String
},
country:{
type:String
},
resetPasswordToken: String,
resetPasswordExpires: Date
});
UserSchema.plugin(passportLocalMongoose);
var User = module.exports = mongoose.model('User', UserSchema);
I am trying to create a model using Sequelize and mysql db.I am trying to post to '/students/register' it keeps giving me an error saying findOne is not a function. I tried requiring my sql but it's not working ..I also tried a different function like findAll and still not working.what seems to be the problem
const Sequelize = require('sequelize');
module.exports = function (sequelize, Sequelize) {
const Stundet = sequelize.define(
'student', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
created: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
}
}, {
timestamps: false
});
module.exports = Stundet;
}
routes
const Student_Info = require("../models/students")
student.post('/register', (req, res) => {
const dataToday = new Date()
const studentData = {
name: req.body.name,
email: req.body.email,
password: req.body.password,
created: dataToday
}
Student_Info.findOne({
where: {
email: req.body.email
}
})
.then(student => {
if (!student) {
bcrypt.hash(req.body.password, 10, (err, hash) => {
studentData.password = hash
Student_Info.create(studentData)
.then(student => {
res.json({
status: student.email + 'registered'
})
})
.catch(err => {
res.send('error' + err)
})
})
} else {
res.json({
error: 'Student already registered'
})
}
})
.catch(err => {
res.send('error' + err)
})
})
module.exports = student;
When you use module.exports, you should return Stundet. You already export the whole function. And I think you should pass DataTypes instead of Sequelize.
Something like this:
module.exports = function (sequelize, DataTypes) {
const Stundet = sequelize.define(
//...
return Stundet;
}
So in your route in order to use your model:
const Sequelize = require('sequelize');
const DataTypes = sequelize.DataTypes;
let sequelize = new Sequelize(...);
const Student = require('../models/students')(sequelize, DataTypes);
I suspect that your Student_Info is null. Does you application successfully connect to the database? It helps to log... e.g.
sequelizeDB
.authenticate()
.then(() => {
console.log('Yes! DB Connection);
...
})
.catch(err => {
console.error('No! Unable to connect to DB', err);
});
... and IMHO the code reads better when you name the DB instance something other than "sequelize".
I'm using sequelize.js for my data store and the github strategy with passport.js. My code is:
app.use(passport.initialize());
app.use(passport.session());
passport.use(new GitHubStrategy({
clientID: '123',
clientSecret: '456',
callbackURL: "" + config.hostname + ":" + config.port + "/auth/github/callback"
}, function(accessToken, refreshToken, profile, done) {
var authProviderQuery, newUser;
console.log('accessToken');
console.log(accessToken);
authProviderQuery = {
authId: profile.id
};
newUser = {
name: profile.username,
email: profile.emails[0].value
};
return DB.AuthProvider.find(authProviderQuery).complete(function(err, dbAuthProvider) {
var prop, _results;
if (err) {
return done(err);
}
if (!dbAuthProvider) {
return DB.User.create(newUser).complete(function(err, dbUser) {
var newAuthProvider;
if (err) {
return done(err);
}
newAuthProvider = {
name: 'github',
oathToken: accessToken,
authId: profile.id,
rawJSON: profile._raw
};
return dbUser.createAuthProvider(newAuthProvider).complete(function(err) {
if (err) {
return done(err);
}
return done(null, dbUser);
});
});
} else {
console.log(dbAuthProvider);
_results = [];
for (prop in dbAuthProvider) {
_results.push(console.log(prop));
}
return _results;
}
});
}));
passport.serializeUser = function(user, done) {
return done(null, user.id);
};
passport.deserializeUser = function(obj, done) {
return DB.User.find({
where: {
id: obj.id
}
}).complete(function(err, dbUser) {
console.log(dbUser);
return done(err, dbUser);
});
};
app.get('/auth/github', passport.authenticate('github'));
app.get("/auth/github/callback", passport.authenticate('github', {
failureRedirect: "/login"
}), function(req, res) {
return console.log('authenticated');
});
When I go to /auth/github, I get the following error:
/Users/mysite/node_modules/mysql/lib/protocol/Parser.js:82
throw err;
^
TypeError: object is not a function
What am I doing wrong?
You are replacing the serializeUser and deserializeUser methods from Passport instead of calling them to assign a (de)serializer - ie. you have
passport.deserializeUser = function(obj, done) {
...
};
when you should have
passport.deserializeUser(function(obj, done) {
...
});
See the documentation: http://passportjs.org/guide/configure/