I’m trying to create a basic login system using Node.js, mongodb and bcrypt.js. The registration is working as expected, however the user login is not, since it only works correctly for the first user in the database, only allowing any other user to login with that first user’s password.
For example, if the database is empty, and I register a user, with username ‘John’ and password ‘helloworld’, and I try to log in using those credentials, it will appear to be successful, however if I create another user, with username ‘Jane’ and password ‘goodbye’, and use those credentials to log in, the programme will return ‘Invalid password.’ However, if I try and log in using the credentials ‘Jane’ and ‘helloworld’, the programme will tell me that it’s been successful.
Here is my code:
server.js
const express = require('express')
const path = require('path')
const mongoose = require('mongoose')
const User = require('./models/user')
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
// JWT Secret
const JWT_SECRET= 'asnotehuaonteihsonet)()*cgighdnh'
// Connects to the MongoDB database
mongoose.connect('mongodb+srv://anousheh1:[email protected]/?retryWrites=true&w=majority')
const app = express()
app.use(express.json())
app.use(express.urlencoded({extended: true}))
app.use('/', express.static('./public'))
app.post('/api/login', async (req, res) => {
const {username, password} = req.body
const user = await User.findOne({username}).lean()
// Checks to see if user is in database
if (!user) {
// return res.json({status: 'error', error: 'Invalid username'})
return res.status(400).json({error: 'Invalid username'})
}
// Compares the password input by the user to the hashed password in the database
if ( await bcrypt.compare(req.body.password, user.password)) {
const token = jwt.sign({id: user._id, username: user.username}, JWT_SECRET)
console.log(token)
return res.status(200).json({status: 200, data: ''})
}else {
res.status(400).json({status: 400, error: 'Invalid password'})
}
})
app.post('/api/register/', async (req, res) => {
const {username, password: plaintext} = req.body
if (!username || typeof username !== 'string') {
// return res.json({status:'error', error:'Missing Username'})
return res.status(400).json({error: 'Invalid Username'})
}
if (!plaintext || typeof plaintext !== 'string') {
return res.status(400).json({error: 'Invalid Password'})
}
const hashedPassword = (await bcrypt.hash(plaintext, 10))
// Use schema to create an instance which will be added to the database
try {
const response = await User.create({
name: username,
password: hashedPassword
})
res.json({status: 200})
console.log(response)
} catch (error) {
if(error.code === 11000) {
// return res.json({status: 'error', error: 'Username Taken'})
return res.status(400).json({error: 'Username Taken'})
}
throw error
}
})
port = 5000
app.listen(port, () => {
console.log(`Server Activated on Port ${port}`)
})
./public/script.js
const regForm = document.getElementById('registrationForm')
regForm.addEventListener('submit', registerUser)
async function registerUser(event) {
event.preventDefault()
const username = document.getElementById('username').value
const password = document.getElementById('password').value
const result = await fetch ('/api/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
// stringify turns object literals into JSON
body: JSON.stringify({
username,
password
})
}).then((res) => res.json())
if (result.status !== 200) {
alert(result.error)
}
console.log(result)
}
./public/scriptLogin.js
const loginForm = document.getElementById('loginForm')
loginForm.addEventListener('submit', loginUser)
async function loginUser (event) {
event.preventDefault()
const username = document.getElementById('username').value
const password = document.getElementById('password').value
const result = await fetch ('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: username,
password: password
})
}).then((res) => res.json())
if (result.status === 200) {
console.log(`Token: ${result.data}`)
alert('Success')
} else {
alert(result.error)
// console.log(user)
// console.log(error)
}
}
./models/user.js
const mongoose = require('mongoose')
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
})
module.exports = mongoose.model('User', UserSchema)
2
Answers
You should change the
UserSchema
to:And
create
a newUser
with:the error came from
'/api/login'
onfindOne
, because you dont have fieldusername
in your collection.or
please consider to use try{}catch(err){}.