0

Context

I am following a tutorial which is titled "Building a Secure User Registration and Login API with Express.js ,MongoDB and JWT"

It uses express bcryptjs jsonwebtoken mongoose to build a simple web server with register/login functionality.

The problem

The problem arise when I send a multitude of requests to /api/register. Server creates many users with same credentials.

Code to reproduce

Server

// Importing required modules
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

// Creating an Express application instance
const app = express();
const PORT = 3000;

// Connect to MongoDB database
mongoose.connect('mongodb://localhost:27017/mydatabase')
    .then(() => {
        console.log('Connected to MongoDB');
    })
    .catch((error) => {
        console.error('Error connecting to MongoDB:', error);
    });

// Define a schema for the User collection
const userSchema = new mongoose.Schema({
    username: String,
    email: String,
    password: String
});

// Create a User model based on the schema
const User = mongoose.model('User', userSchema);

// Middleware to parse JSON bodies
app.use(express.json());

// Route to register a new user
app.post('/api/register', async (req, res) => {
    try {
        // Check if the email already exists
        const existingUser = await User.findOne({email: req.body.email});
        if (existingUser) {
            return res.status(400).json({error: 'Email already exists'});
        }

        // Hash the password
        const hashedPassword = await bcrypt.hash(req.body.password, 10);

        // Create a new user
        const newUser = new User({
            username: req.body.username,
            email: req.body.email,
            password: hashedPassword
        });

        await newUser.save();
        console.log(newUser)
        res.status(201).json({message: 'User registered successfully'});
    } catch (error) {
        console.log('Internal server error')
        res.status(500).json({error: 'Internal server error'});
    }
});

// Start the server
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

Client

(() => {
    const send = () => fetch('http://127.0.0.1:3000/api/register', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            "username": "testuser", "email": "[email protected]", "password": "testpassword"
        })
    }).then()

    for (let i = 0; i < 10; i++) send()
})()

Output

{
  username: 'testuser',
  email: '[email protected]',
  password: '$2a$10$5Jo01CQ797EuMrujH49Of.OmFY4n6yIX.4VgU8FOEhXRmr.CxHnRy',
  _id: new ObjectId('668cf24a08fa6ed9fbf442d5'),
  __v: 0
}
...9 more users created
5
  • whast the question
    – cmgchess
    Commented Jul 9 at 8:26
  • 1
    you are sending same password 10 times, so the server will obviously create many users with same credentials.
    – sidgate
    Commented Jul 9 at 8:54
  • Maybe you want to know why your check for existing email isn't working? If so, please edit question's title
    – pierpy
    Commented Jul 9 at 9:22
  • You need to add a unique index to either the username, email or both. Delete all the users from your collection then update your schema for example email: {type: String, unique: true} or username: {type: String, unique: true}. That will ensure only unique values are inserted to the collection.
    – jQueeny
    Commented Jul 9 at 11:24
  • Add a pinch of salt instead of constant 10 to get different hashes.
    – Alex Blex
    Commented Jul 9 at 23:58

1 Answer 1

1

This is a common issue with asynchronous operations. It is like 10 people asked at the same time if there is a chair available. All 10 of them gets the save answer yes but only one of them can sit on it.

In order to solve this, you should validation to the model

const userSchema = new mongoose.Schema({
  username: { type: String, unique: true },
  email: { type: String, unique: true },
  password: String,
});

Not the answer you're looking for? Browse other questions tagged or ask your own question.