Day 4: Authentication Using JWT (JSON Web Tokens)


In this tutorial, you’ll learn how to implement authentication in your Express API using JWT. By the end of today’s lesson, users will be able to register, log in, and access protected routes using a token-based authentication system.


What You Will Learn Today:

  1. Installing and setting up JWT for authentication
  2. Creating user registration and login routes
  3. Generating JWT tokens upon successful login
  4. Protecting API routes using JWT middleware
  5. Testing authentication with Postman

Step 1: Installing JWT and Bcrypt

Before we implement authentication, we need two libraries:

  • JWT: For generating and verifying tokens.
  • Bcrypt: For securely hashing passwords before storing them in the database.
  1. Install these packages by running the following command:
npm install jsonwebtoken bcryptjs

Step 2: Creating User Registration and Login Routes

Let’s first set up routes for user registration and login. We’ll hash the password using bcrypt and generate a JWT upon successful login.

User Registration

  1. Open routes/users.js and add the following route for user registration:
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const router = express.Router();
const User = require('../models/User');
const userController = require('../controllers/userController');

// Register a new user
router.post('/register', async (req, res) => {
  const { name, email, password } = req.body;

  try {
    // Check if the user already exists
    const existingUser = await User.findOne({ email });
    if (existingUser) {
      return res.status(400).json({ message: 'User already exists' });
    }

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

    // Create a new user
    const newUser = new User({ name, email, password: hashedPassword });
    const savedUser = await newUser.save();

    res.status(201).json(savedUser);
  } catch (error) {
    res.status(500).json({ message: 'Error registering user', error });
  }
});

Explanation:

  • bcrypt.hash(): This function hashes the user’s password with a salt, ensuring that passwords are stored securely.
  • Check for existing user: We first check if a user with the given email already exists to prevent duplicate registrations.
See also  Deep Dive: Orchestrating a Development Galaxy with Jenkins, Jira, Selenium, and Docker

User Login

Next, let’s create a route for user login. When the user logs in, we’ll verify their email and password, and if successful, we’ll generate a JWT.

  1. Add the following route for login:
// User login
router.post('/login', async (req, res) => {
  const { email, password } = req.body;

  try {
    // Check if the user exists
    const user = await User.findOne({ email });
    if (!user) {
      return res.status(404).json({ message: 'User not found' });
    }

    // Check if the password is correct
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return res.status(400).json({ message: 'Invalid credentials' });
    }

    // Generate a JWT
    const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });

    res.json({ token });
  } catch (error) {
    res.status(500).json({ message: 'Error logging in', error });
  }
});

Explanation:

  • bcrypt.compare(): This function compares the provided password with the hashed password stored in the database.
  • jwt.sign(): This generates a JWT token, signed with a secret key (process.env.JWT_SECRET). The token will expire in 1 hour.

Step 3: Protecting Routes with JWT Middleware

Now that we have JWT tokens, we can protect certain routes by ensuring that the user provides a valid token before accessing those routes. We’ll create middleware to verify the token.

Creating JWT Middleware

  1. Inside your project directory, create a new folder called middleware and a file called auth.js.
mkdir middleware
touch middleware/auth.js
  1. Open middleware/auth.js and add the following code to verify JWT tokens:
const jwt = require('jsonwebtoken');

const auth = (req, res, next) => {
  const token = req.header('x-auth-token');

  // Check if token exists
  if (!token) {
    return res.status(401).json({ message: 'No token, authorization denied' });
  }

  try {
    // Verify token
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded; // Add the decoded user ID to the request object
    next();
  } catch (error) {
    res.status(401).json({ message: 'Invalid token' });
  }
};

module.exports = auth;

Explanation:

  • jwt.verify(): Verifies the provided token using the secret key. If valid, it adds the user ID to the request object (req.user).
  • next(): Passes control to the next middleware or route handler if the token is valid.
See also  Day 9: Adding Typing Indicators and Presence (Online/Offline) Status

Protecting Routes

Let’s protect the GET /api/users route so that only authenticated users can access it.

  1. Open routes/users.js and modify the GET route to use the auth middleware:
const auth = require('../middleware/auth');

// Get all users (protected route)
router.get('/', auth, userController.getAllUsers);

Explanation:

  • The auth middleware is added before the getAllUsers controller. This ensures that the token is verified before accessing the route.

Step 4: Testing Authentication with Postman

Let’s test the registration, login, and protected routes using Postman.

1. Register a New User

  1. Open Postman and make a POST request to http://localhost:5000/api/users/register with the following JSON body:
{
  "name": "John Doe",
  "email": "[email protected]",
  "password": "password123"
}
  1. If the registration is successful, you should receive a response with the newly created user.

2. Log In as the Registered User

  1. Make a POST request to http://localhost:5000/api/users/login with the following JSON body:
{
  "email": "[email protected]",
  "password": "password123"
}
  1. If the login is successful, you’ll receive a response containing the JWT token:
{
  "token": "your_jwt_token_here"
}

3. Access the Protected Route

  1. Now, let’s access the protected GET /api/users route. In Postman:
  • Set the request method to GET.
  • URL: http://localhost:5000/api/users.
  • In the Headers section, add a header:
    • Key: x-auth-token
    • Value: your_jwt_token_here (replace with the token you received from the login request).
  1. Send the request, and you should receive a list of users if the token is valid.

If you try to access the route without a token or with an invalid token, you’ll receive a 401 Unauthorized error.


Step 5: Recap and Summary

In this tutorial, you learned how to implement authentication using JWT (JSON Web Tokens) in your Express API. Here’s a quick summary of what you’ve done:

  • Installed jsonwebtoken and bcryptjs for handling authentication and password hashing.
  • Created user registration and login routes.
  • Generated JWT tokens upon successful login.
  • Created middleware to protect routes using JWT.
  • Tested the authentication flow using Postman.
See also  Day 8: Implementing Deep Linking in React Native

With authentication in place, your API is now secured, and only authorized users can access protected routes!


Next Up: Day 5 – Implementing Middleware and Error Handling

In Day 5, we’ll dive into adding custom middleware for logging, validation, and error handling in your Express API. This will help you manage errors and maintain clean, consistent responses.

Stay tuned for more advanced features tomorrow!


Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.