Implementing user authentication with JWT in Node.js

Implementing User Authentication with JWT in Node.js

In today’s digital landscape, securing user data and ensuring safe access to applications is crucial. One effective way to manage user authentication is through JSON Web Tokens (JWT). In this article, we will explore how to implement user authentication using JWT in a Node.js application. We’ll cover definitions, use cases, and provide actionable coding insights complete with examples to guide you through the process.

What is JWT?

JSON Web Token, or JWT, is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with HMAC algorithm) or a public/private key pair using RSA or ECDSA.

Benefits of Using JWT for Authentication

  • Compact: JWTs are small in size, making them easy to send over HTTP headers.
  • Self-contained: They contain all the necessary user information, reducing the need for multiple database queries.
  • Cross-domain: JWTs are ideal for single-page applications and can be used across different domains.
  • Stateless: Since the server does not need to keep a session, it scales well with increasing user numbers.

Use Cases for JWT

JWTs are particularly beneficial in scenarios such as:

  • Single Page Applications (SPAs): They allow for seamless user experience without frequent server calls.
  • Mobile Applications: JWTs can be used to authenticate API requests from mobile devices.
  • Microservices: They enable secure communication between different microservices.

Step-by-Step Implementation of JWT Authentication in Node.js

Prerequisites

Before we start coding, ensure you have the following:

  • Node.js installed on your machine.
  • A basic understanding of JavaScript and Node.js.
  • A package manager like npm or yarn.

Setting Up the Project

  1. Create a new directory for your project: bash mkdir jwt-auth-example cd jwt-auth-example

  2. Initialize a new Node.js project: bash npm init -y

  3. Install required dependencies: bash npm install express jsonwebtoken bcryptjs body-parser

Building the Server

Create a file named server.js and set up a basic Express server:

const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');

const app = express();
const PORT = process.env.PORT || 3000;
const SECRET_KEY = 'your_secret_key';

app.use(bodyParser.json());

User Registration

Next, let’s implement a user registration endpoint where users can sign up:

let users = []; // In-memory user storage for demonstration purposes

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

    // Check if user already exists
    const existingUser = users.find(user => user.username === username);
    if (existingUser) {
        return res.status(400).send('User already exists.');
    }

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

    // Save user
    users.push({ username, password: hashedPassword });
    res.status(201).send('User registered successfully.');
});

User Login and Token Generation

Now, let’s implement the login functionality that generates a JWT upon successful authentication:

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

    if (!user || !(await bcrypt.compare(password, user.password))) {
        return res.status(401).send('Invalid credentials.');
    }

    // Create a token
    const token = jwt.sign({ username: user.username }, SECRET_KEY, { expiresIn: '1h' });
    res.json({ token });
});

Middleware for Protected Routes

To protect certain routes, we can create a middleware function to verify the JWT:

function authenticateToken(req, res, next) {
    const token = req.headers['authorization'] && req.headers['authorization'].split(' ')[1];
    if (!token) return res.sendStatus(401);

    jwt.verify(token, SECRET_KEY, (err, user) => {
        if (err) return res.sendStatus(403);
        req.user = user; // Save user info for future use
        next();
    });
}

Creating a Protected Route

Let’s create a route that only authenticated users can access:

app.get('/protected', authenticateToken, (req, res) => {
    res.send(`Hello ${req.user.username}, you have accessed a protected route.`);
});

Starting the Server

Finally, add the code to start your server:

app.listen(PORT, () => {
    console.log(`Server running on http://localhost:${PORT}`);
});

Testing the Application

  1. Register a user:
  2. Send a POST request to http://localhost:3000/register with a JSON body containing username and password.

  3. Login with the registered user:

  4. Send a POST request to http://localhost:3000/login to receive a JWT.

  5. Access the protected route:

  6. Use the token received from the login to make a GET request to http://localhost:3000/protected by including it in the Authorization header.

Troubleshooting Common Issues

  • Invalid Token: Ensure that the token is correctly passed in the Authorization header.
  • User Already Exists: Check the registration logic; make sure the username is unique.
  • Password Mismatch: Ensure you are hashing and comparing passwords correctly.

Conclusion

Implementing JWT for user authentication in a Node.js application provides a secure and scalable solution to manage user sessions. By following the steps outlined in this article, you can set up a basic authentication system that can be expanded and modified to suit your specific needs. With JWT, you can enhance the user experience while ensuring data security, making it an essential tool in modern web development. 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.