DEV Community

Cover image for Part 8: Implementing Authentication and Authorization in Node.js
Dipak Ahirav
Dipak Ahirav

Posted on

Part 8: Implementing Authentication and Authorization in Node.js

Security is a critical aspect of web development, and understanding how to implement authentication and authorization is essential for any developer. In this part of our Node.js series, we will explore how to secure your application by implementing a simple authentication system. We'll use JSON Web Tokens (JWT) for authentication and middleware for authorization.

please subscribe to my YouTube channel to support my channel and get more web development tutorials.

Understanding Authentication and Authorization

  • Authentication: The process of verifying the identity of a user. Typically, this involves checking a username and password.
  • Authorization: The process of determining if a user has permission to perform a certain action or access certain resources.

Setting Up the Project

Let's start by setting up a new Express project. If you haven’t already, initialize a new project and install the necessary dependencies:

npm init -y
npm install express bcryptjs jsonwebtoken body-parser mongoose
Enter fullscreen mode Exit fullscreen mode

Connecting to MongoDB

First, we need to connect our application to MongoDB. If you need a refresher on connecting to MongoDB, refer to Part 7 of this series.

database.js

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/auth_demo', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useCreateIndex: true
});

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
  console.log('Connected to MongoDB');
});

module.exports = mongoose;
Enter fullscreen mode Exit fullscreen mode

Defining User Model

We need a user model to store user information, including hashed passwords.

userModel.js

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

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

userSchema.pre('save', async function (next) {
  if (this.isModified('password') || this.isNew) {
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
  }
  next();
});

userSchema.methods.comparePassword = async function (password) {
  return await bcrypt.compare(password, this.password);
};

const User = mongoose.model('User', userSchema);

module.exports = User;
Enter fullscreen mode Exit fullscreen mode

Setting Up Express Server

Next, set up the Express server and create routes for user registration and login.

app.js

const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const User = require('./userModel');
const mongoose = require('./database');

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

const JWT_SECRET = 'your_jwt_secret';

// User Registration
app.post('/register', async (req, res) => {
  try {
    const { username, password } = req.body;
    const user = new User({ username, password });
    await user.save();
    res.status(201).send('User registered successfully');
  } catch (err) {
    res.status(400).send('Error registering user');
  }
});

// User Login
app.post('/login', async (req, res) => {
  try {
    const { username, password } = req.body;
    const user = await User.findOne({ username });
    if (!user || !(await user.comparePassword(password))) {
      return res.status(401).send('Invalid username or password');
    }
    const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '1h' });
    res.send({ token });
  } catch (err) {
    res.status(400).send('Error logging in');
  }
});

// Middleware to Protect Routes
const authMiddleware = (req, res, next) => {
  const token = req.headers['authorization'];
  if (!token) {
    return res.status(401).send('Access denied. No token provided.');
  }
  try {
    const decoded = jwt.verify(token, JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).send('Invalid token');
  }
};

// Protected Route
app.get('/protected', authMiddleware, (req, res) => {
  res.send('This is a protected route');
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});
Enter fullscreen mode Exit fullscreen mode

Testing the Application

  1. Register a User:

    • Send a POST request to /register with a JSON body containing username and password.
  2. Login a User:

    • Send a POST request to /login with the same credentials.
    • If successful, you will receive a JWT token.
  3. Access a Protected Route:

    • Send a GET request to /protected with the token in the Authorization header.

Conclusion

By implementing authentication and authorization, you can protect your application’s routes and ensure that only authenticated users can access certain resources. In the next part of our series, we will delve into building RESTful APIs using Express and best practices for structuring your application.

Stay tuned for more advanced Node.js development techniques!


Follow me for more tutorials and tips on web development. Feel free to leave comments or questions below!

Follow and Subscribe:

Top comments (0)