skip to Main Content

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


  1. You should change the UserSchema to:

    const UserSchema = new mongoose.Schema({
        username: {
            type: String,
            required: true,
            unique: true
        },
        password: {
            type: String,
            required: true
        }
    })
    

    And create a new User with:

    const response = await User.create({
        username,
        password: hashedPassword
    })
    
    Login or Signup to reply.
  2. the error came from '/api/login' on findOne, because you dont have field username in your collection.

    const user = await User.findOne({name: username}).lean()
    

    or

    const {username: name, password} = req.body
    const user = await User.findOne({name}).lean()
    

    please consider to use try{}catch(err){}.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search