DEV Community

Seif Ahmed
Seif Ahmed

Posted on

Building a Secure Authentication System

This guide details the logic for implementing a secure, session-based user login system using Node.js, Mongoose and Bcrypt.


📝 Step-by-Step Implementation:

1. Database Lookup

When a user submits their credentials, the system queries MongoDB to locate the user profile.

  • Method: findOne({ username }) via Mongoose.
  • Security Rule: If the username does not exist, halt execution immediately. Return a 401 Unauthorized status.

2. Password Verification

If the user account exists, the system compares the plain-text input password against the hashed password stored in the database.

  • Method: await bcrypt.compare(password, user.password).
  • Security Rule: If the comparison returns false, halt execution. Return a 401 Unauthorized status.

3. Session Management

Once both checks pass, the system initializes a secure session to keep the user authenticated across subsequent requests.

  • State Flags:
    • req.session.isLoggedIn = true
    • req.session.userId = user._id
  • Response: Return a 200 OK status with a success message.

🔒 Security Best Practices Implemented:

  • Generic Error Messages: Both missing usernames and incorrect passwords return the exact same message: "Invalid username or password". This prevents attackers from brute-forcing and enumerating valid usernames.
  • Cryptographic Hashing: Passwords are never stored or compared in plain text. Bcrypt handles salt generation automatically to protect against rainbow table attacks.
  • Stateful Sessions: Using server-side sessions keeps user identity secure and reduces the risk of token theft common in purely client-side storage.

💻 Quick Code Example:

app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  try {
    // 1. Check if the user exists
    const user = await User.findOne({ username });
    if (!user) {
      return res.status(401).json({ message: "Invalid username or password" });
    }

    // 2. Verify the password
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return res.status(401).json({ message: "Invalid username or password" });
    }

    // 3. Establish session data
    req.session.isLoggedIn = true;
    req.session.userId = user._id;

    return res.status(200).json({ message: "Congrats! You are logged in!" });

  } catch (error) {
    return res.status(500).json({ message: "Internal server error" });
  }
});
Enter fullscreen mode Exit fullscreen mode

If you found this guide helpful, please consider giving it a like!
Thanks for reading!

Top comments (0)