-1

i'm have trouble with comparing stored hashed passwords with user entered password in my login endpoint to give users access, below is my server.js file where my signup and login endpoints are.

const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');
const cors = require('cors');

const secretKey = require('./jwt-token');

const app = express();
app.use(cors());
app.use(express.json());

// MongoDB connection URI
const uri = 'mongodb://localhost:27017/final-year-project';

// Connect to the MongoDB database
mongoose
  .connect(uri, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => {
    console.log('Connected to the database');
    app.listen(3000);
    console.log('app connected on port 3000');
  })
  .catch((error) => {
    console.error('Failed to connect to the database:', error);
  });

// Define the user schema
const userSchema = new mongoose.Schema({
  firstName: { type: String, required: true },
  lastName: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  role: { type: String, required: true },
  password: { type: String, required: true },
}, { collection: 'users' });

// Define the user model
const User = mongoose.model('User', userSchema);

class AuthResponseData {
  constructor(user) {
    this.user = user;
  }
}

// Signup endpoint
app.post('/signup', async (req, res) => {
    try {
      // Extract user data from request body
      const { 
        firstName, 
        lastName, 
        email, 
        role,
        password } = req.body;
  
      // Check if email is already taken
      const existingUser = await User.findOne({ email });
      if (existingUser) {
        return res.status(400).json({ message: 'Email already exists' });
      }
  
      // Set a default password if the provided password is empty
      let plainTextPassword = password;
      if (!plainTextPassword) {
        plainTextPassword = 'defaultPassword123';
      }
  
      // Generate a salt asynchronously
      bcrypt.genSalt(10, (saltError, salt) => {
        if (saltError) {
          console.error('Error generating salt:', saltError);
          return res.status(500).json({ message: 'Internal server error' });
        }
  
        // Hash the password asynchronously
        bcrypt.hash(plainTextPassword, salt, async (hashError, hashedPassword) => {
          if (hashError) {
            console.error('Error hashing password:', hashError);
            return res.status(500).json({ message: 'Internal server error' });
          }
  
          try {
            // Create a new user object
            const newUser = new User({
              firstName,
              lastName,
              email,
              role,
              password: hashedPassword,
            });
  
            // Save the user to the database
            await newUser.save();
  
            // Generate a JSON Web Token (JWT)
            const token = jwt.sign({ email: newUser.email }, secretKey);
  
            // Set token expiration date (e.g., 1 hour from now)
            const expirationDate = new Date().getTime() + 3600000;
  
            // Create a new user instance
            const user = {
              firstName: newUser.firstName,
              lastName: newUser.lastName,
              email: newUser.email,
              role: newUser.role,
              id: newUser._id,
              _token: token,
              _tokenExpirationDate: expirationDate,
            };
  
            // Return the authentication response with user details
            const authResponse = new AuthResponseData(user);
  
            res.status(201).json(authResponse);
          } catch (error) {
            console.error(error);
            res.status(500).json({ message: 'Internal server error' });
          }
        });
      });
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Internal server error' });
    }
    console.log(req.body)
  });
  
// Login endpoint
app.post('/login', async (req, res) => {
  try {
    // Extract user data from request body
    const { email, password } = req.body;
    const userEmail = req.body.email;
    const userPassword = req.body.password;

    console.log(userEmail);
    console.log(userPassword);

    // Find the user in the database
    const user = await User.findOne({ email });
    if (!user) {
      return res.status(401).json({ message: 'Invalid email or password' });
    };

    console.log('user verified');

    hashedPasswordFromDb = user.password;

    console.log(hashedPasswordFromDb);
    console.log(userPassword);

    // Compare passwords
    bcrypt.compare(userPassword, hashedPasswordFromDb, (passwordError, passwordMatch) => {
      if (passwordError) {
        console.error('Error comparing passwords:', passwordError);
        return res.status(500).json({ message: 'Internal server error' });
      }

      console.log(passwordError);
      console.log(passwordMatch);

      if (!passwordMatch) {
        return res.status(401).json({ message: 'Invalid email or password' });
      }

      console.log(passwordMatch);

      // Generate a JSON Web Token (JWT)
      const token = jwt.sign({ email: user.email }, secretKey);

      // Set token expiration date (e.g., 1 hour from now)
      const expirationDate = new Date().getTime() + 3600000;

      // Create a new user instance
      const loggedInUser = {
        firstName: user.firstName,
        lastName: user.lastName,
        email: user.email,
        role: user.role,
        id: user._id,
        _token: token,
        _tokenExpirationDate: expirationDate,
      };

      // Return the authentication response with user details
      const authResponse = new AuthResponseData(loggedInUser);

      res.status(200).json(authResponse);
    });

  } catch (error) {
    console.error('Error:', error); // Log the detailed error message
    console.error('Stack trace:', error.stack); // Log the stack trace

    res.status(500).json({ message: 'Internal server error' });
  }
}); 

i logged things onto the console at intervals to see where the error starts from cause an error isn't logged onto the console and the code breaks here:

if (!passwordMatch) {
        return res.status(401).json({ message: 'Invalid email or password' });
      }

I tried hashing the user entered password to compare with the stored hashed password and also comparing directly but to no avail.

1 Answers1

0

I can't really reproduce your error. As a tip independent of that I would recommend you to use the JavaScript alternative of bcrypt (bcryptjs):

bcrypsjs npm package

npm i bcryptjs

The package is compatible to bcrypt and implemented purely in Javascript. I had no problems with it when hashing and comparing the entries. The reason why you could potentially experience some compatibility issues is explained in this answer:

Why is importing bcrypt causing a "Cannot find module napi-v3/bcrypt_lib.node" error?

I've tested it, just have a look here:

https://stackblitz.com/edit/stackblitz-starters-skvmay?file=index.js

DarkBee
  • 16,592
  • 6
  • 46
  • 58
Schabbi
  • 131
  • 6