How to implement user authentication in a Node.js application

How to Implement User Authentication in a Node.js Application

User authentication is a crucial aspect of modern web applications, ensuring that users can securely log in and access their personal information. Node.js, with its asynchronous nature and robust ecosystem, provides an excellent platform for building secure authentication systems. In this article, we’ll explore the step-by-step process of implementing user authentication in a Node.js application, complete with code snippets and actionable insights.

Understanding User Authentication

What is User Authentication?

User authentication is the process of verifying the identity of a user attempting to access a system. It typically involves confirming credentials, such as usernames and passwords, and ensuring that users have the appropriate permissions to access specific resources.

Use Cases for User Authentication

  • Web Applications: Protect user data and personalize experiences.
  • APIs: Secure API endpoints from unauthorized access.
  • Mobile Applications: Manage user sessions and data securely.
  • Admin Panels: Restrict access to sensitive administrative features.

Setting Up the Environment

Before we dive into the implementation, ensure you have the following prerequisites:

  1. Node.js: Make sure you have Node.js installed. You can download it from nodejs.org.
  2. npm: Node Package Manager (npm) is bundled with Node.js.
  3. Express: A minimal and flexible Node.js web application framework.
  4. MongoDB: A NoSQL database to store user credentials.
  5. Mongoose: An ODM (Object Data Modeling) library for MongoDB and Node.js.
  6. bcrypt: A library to hash passwords.
  7. jsonwebtoken: A library to create and verify JSON Web Tokens (JWT).

You can set up your project by running the following commands in your terminal:

mkdir user-auth
cd user-auth
npm init -y
npm install express mongoose bcrypt jsonwebtoken dotenv

Creating the Application Structure

Create the following file structure:

user-auth/
├── .env
├── server.js
├── models/
│   └── User.js
├── routes/
│   └── auth.js
└── middleware/
    └── auth.js

Step 1: Setting Up the User Model

Create a User.js model in the models directory to define the schema for user data.

// models/User.js
const mongoose = require('mongoose');

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

module.exports = mongoose.model('User', userSchema);

Step 2: Creating Authentication Routes

Next, create an auth.js file in the routes directory to handle user registration and login.

// routes/auth.js
const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const router = express.Router();

// Register Route
router.post('/register', async (req, res) => {
  const { username, password } = req.body;
  const hashedPassword = await bcrypt.hash(password, 10);

  const user = new User({
    username,
    password: hashedPassword,
  });

  try {
    await user.save();
    res.status(201).send('User registered successfully');
  } catch (error) {
    res.status(400).send('Error registering user');
  }
});

// Login Route
router.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = await User.findOne({ username });

  if (user && (await bcrypt.compare(password, user.password))) {
    const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, {
      expiresIn: '1h',
    });
    res.json({ token });
  } else {
    res.status(401).send('Invalid credentials');
  }
});

module.exports = router;

Step 3: Middleware for Protected Routes

Create a middleware function to protect routes, ensuring that only authenticated users can access them.

// middleware/auth.js
const jwt = require('jsonwebtoken');

const auth = (req, res, next) => {
  const token = req.header('Authorization')?.split(' ')[1];
  if (!token) return res.status(403).send('Access denied');

  try {
    const verified = jwt.verify(token, process.env.JWT_SECRET);
    req.user = verified;
    next();
  } catch (error) {
    res.status(400).send('Invalid token');
  }
};

module.exports = auth;

Step 4: Setting Up the Express Server

Now, create the main server file to connect everything.

// server.js
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const authRoutes = require('./routes/auth');
const app = express();

dotenv.config();
app.use(express.json());

mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log('MongoDB connected'))
  .catch(err => console.log(err));

app.use('/api/auth', authRoutes);

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Step 5: Testing the Application

You can test the application using tools like Postman or CURL. Here’s how to register and login:

  1. Register:
  2. POST to http://localhost:3000/api/auth/register with JSON body: json { "username": "testuser", "password": "password123" }

  3. Login:

  4. POST to http://localhost:3000/api/auth/login with JSON body: json { "username": "testuser", "password": "password123" }

If successful, you will receive a JWT token which you can use for accessing protected routes.

Conclusion

Implementing user authentication in a Node.js application is straightforward with the right tools and libraries. By following the steps outlined in this article, you should be able to set up a secure authentication system using Express, MongoDB, and JWT. Remember to handle error cases, validate inputs, and consider additional security measures such as HTTPS and rate limiting for a production environment.

With this foundational knowledge, you can now expand your application further, integrate third-party authentication providers, or enhance user experience with features like password recovery and account verification. Happy coding!

SR
Syed
Rizwan

About the Author

Syed Rizwan is a Machine Learning Engineer with 5 years of experience in AI, IoT, and Industrial Automation.