JWT Authentication With Node.js

JWT Authentication With Node.js

Introduction to Authentication and JWT

Authentication simply is the process of validating a user or an entity attempting to access a resource. It can be perceived as an act of confirmation to see if the said user or entity is who they claim to be before granting access to protected data, information or functionalities.

Authentication can be illustrated using a simple example: before using a mobile device, you are required to unlock it with methods like face ID, password, or PIN before accessing any resources. If you enter an incorrect password or PIN, you are denied access to the device's content. This process of verifying your identity is known as authentication.

JWT(JSON Web Token) is an open standard(commonly accepted specification) that defines a compact and self-contained way to securely transmit information between parties as a JSON object. It consists of three parts: a header, a payload and a signature.

Picture this: You've got a super top-secret message that you need to send to your friends. But here's the catch: you can't let anyone else read or mess with it along the way. So, what's the solution? Put it in the JWT, aka the "super-duper secret envelope of awesomeness!"

Now, let's break it down. This incredible envelope has three major components:

  • The Header: Think of it as the envelope's fancy label. It shouts out loud, "Hey, world! This is a JWT, and it's locked with an epic secret code!"

  • The Payload: Inside the envelope lies the juicy stuff—your actual message! It can contain anything you want to share, from your name to your favourite ice cream flavour (super important, obviously).

  • The Signature: This is where the magic happens. It's like a mind-blowing lock on the envelope, created using a secret key that only you and your friends possess. This lock guarantees that no sneaky intruder can open the envelope or alter your message without the right key (Hehe, take that, unwanted meddlers!).

When you send the JWT to your friends, they can look at the label(header) which tells them "Yo! This is a JWT". Then they can read the message(payload) and be sure it hasn't been changed thanks to the lock(signature).

In a nutshell, JWT acts like a secure envelope for your secret message, ensuring it remains safe during its journey from one place to another. This lightweight and reliable mechanism is widely used for authentication in web applications. Its simplicity, scalability, and compatibility have made it a favoured choice for implementing token-based authentication systems that keeps user data protected and maintain the integrity of communication.

Setting up a JWT Node.js Project

Alright, it is time for the fun part, let's dive into setting up a Node.js project. Here is a step-by-step guide to get you started:

  • Install Node.js: Ah oy! First things first, you need to have Node.js installed on your computer. You can download and install it from the official Node.js website. Choose the LTS(Long-Term Support) version for stability.

  • Initialize a New Project: Open your terminal or command prompt and create a new folder for your project. Navigate into that folder and run the following command to initialize a new Node.js project.

      npm init
    

    This command will prompt you to enter some information about your project, such as the name, version, description etc. You can press "Enter" to use the default values for most of these, or you can provide your own.

  • Create Project Structure: Now that you have your project initialized, it is time to create the necessary folder structure. You can have something like this(for this simple demonstration):

      - your-project-folder
        |- src
          |- controllers
            |- authController.js
          |- routes
            |- authRoutes.js
          |- index.js
        |- package.json
    

    The src folder would contain your application's source code, and index.js will be the entry point of your application.

  • Install Dependencies: Remember, first you have to get the ingredients before you can cook a meal and now it is time to get the ingredients needed for this project 🤓. Okay, all we actually need to do is to install express, jsonwebtoken and bcrypt.

      npm install express jsonwebtoken bcrypt
    

Write your code

After getting the ingredients, you put the pot on fire and start cooking but in our case, you get to open your favourite code editor to start coding. We are going to start out with the index.js file (or any other name you prefer).

  • Here is my index.js file which is the entry point.

      const express = require('express');
      const app = express();
      const authRoutes = require('./routes/authRouter')
    
      const port = 4000;
    
      //Body Parser
      app.use(express.json());
    
      app.use('/api/auth', authRoutes);
    
      app.get('/', (req, res) => {
          res.send('Hello, World!')
      });
    
      app.listen(port, () => {
          console.log(`The fun is at http://localhost:${port}`);
      })
    
  • Create a authRoutes.js file inside the routes folder:

      // routes/authRoutes.js
      const express = require('express');
      const router = express.Router();
      const { register, login } = require('../controllers/authController');
    
      router.post('/register', register);
      router.post('/login', login);
    
      module.exports = router;
    
  • Create a authController.js file inside the controller folder:

      // controllers/authController.js
      const bcrypt = require('bcrypt');
      const jwt = require('jsonwebtoken');
    
      // Replace this with your own secret key for signing the tokens
      const secretKey = 'your-secret-key';
    
      const users = []; // Replace this with your database
    
      exports.register(req, res) => {
      //Get the username and password from the body of the request
      const {username, password} = req.body;
      //Hash the passord
      const hashedPassword = bcrypt.hashSync(password, 10);
      //Save user to the database(array)
      users.push({username, password: hashedPassord});
      //Return a "success" message and status code
      res.status(201).json({msg: "User registered successfully"});
      }
    
      exports.login(req, res) => {
          //Get the username and password from the body of the request
          const {username, password} = req.body;
          //Find user by username
          const user = users.find((u)=>{u.username = username});
          //If user doesn't exist or password doesn't match, throw an error
          if(!user || !bcrypt.compareSync(password, user.password)) {
              return res.status(401).json({msg: 'Invalid Credentials'});
          }
          //Return a JWT token and a "success" message and status code
          const token = jwt.sign({username}, secretKey, {expiresIn: '1hr'});
          res.status(200).json({msg: 'Login succesful', token});
      }
    

Phew 😮‍💨, I guess I had to move my fingers a bit for that. Well, now it is time to run our app and this is the secret incantation:

node src/index.js

Yay! 🍾 we just created a basic authentication with JWT and it is now up and running. This example provides a minimal implementation for registration and login. And remember that in a real-world scenario, you would store users in a database and handle token validation more securely.

To test the endpoints, you can use tools like Postman or cURL. For example:

After a successful login, you'll receive a JWT token that you can use for authenticating subsequent requests to protected routes.