<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sibabale Joja</title>
    <description>The latest articles on DEV Community by Sibabale Joja (@sibabale).</description>
    <link>https://dev.to/sibabale</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2308470%2F9f75551e-a948-44ac-abdc-e33336d8f9f9.jpg</url>
      <title>DEV Community: Sibabale Joja</title>
      <link>https://dev.to/sibabale</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sibabale"/>
    <language>en</language>
    <item>
      <title>Building a Token Blacklisting System with Redis Cloud in Node.js</title>
      <dc:creator>Sibabale Joja</dc:creator>
      <pubDate>Tue, 05 Nov 2024 10:15:53 +0000</pubDate>
      <link>https://dev.to/sibabale/building-a-token-blacklisting-system-with-redis-cloud-in-nodejs-475m</link>
      <guid>https://dev.to/sibabale/building-a-token-blacklisting-system-with-redis-cloud-in-nodejs-475m</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Building a Token Blacklisting System with Redis Cloud in Node.js&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F19008%2F1%2A1vZ3IPso1bLYhiKoTwGkjg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F19008%2F1%2A1vZ3IPso1bLYhiKoTwGkjg.jpeg" alt="Photo by [Mohammad Rahmani](https://unsplash.com/@afgprogrammer?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash) on [Unsplash](https://unsplash.com/photos/black-flat-screen-computer-monitor-CDBkMNZmd7o?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash)" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this guide, we’ll walk through creating a token blacklisting system in a Node.js application. Our approach will use &lt;strong&gt;Redis Cloud&lt;/strong&gt; for storing blacklisted tokens, ensuring tokens cannot be reused after logout. Redis Cloud provides a convenient way to manage our Redis setup without hosting and managing the infrastructure ourselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Token Blacklisting?
&lt;/h3&gt;

&lt;p&gt;Token-based authentication is widely used in modern applications, and JSON Web Tokens (JWTs) are a popular choice. However, JWTs remain valid until they expire, even after a user logs out. To address this, we can “blacklist” tokens upon logout, ensuring they cannot be reused.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Redis Cloud
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Redis Cloud account&lt;/strong&gt;: Go to &lt;a href="https://app.redislabs.com/" rel="noopener noreferrer"&gt;Redis Cloud&lt;/a&gt; and sign up or log in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Redis instance:&lt;/strong&gt; Create a Redis database instance, if one is not created. After setup, you’ll be provided with:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Public endpoint:&lt;/strong&gt; e.g., (redis-12345.c56.us-east-1–3.ec2.cloud.redislabs.com:18285)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Port:&lt;/strong&gt; This will be the last 5 digits on your &lt;em&gt;Public endpoint&lt;/em&gt;. Cut them and delete the semicolon (we will use it later).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Password:&lt;/strong&gt; Scroll down to the security section and copy the &lt;em&gt;Default user password&lt;/em&gt; (we will use it later)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Store credentials securely&lt;/strong&gt; For security, never hardcode these details in your code. Instead, we’ll use environment variables to load them dynamically.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Configuring Redis in Node.js
&lt;/h3&gt;

&lt;p&gt;First, initialize the project&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir token-blacklist
cd token-blacklist
npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, install the necessary packages:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install dotenv ioredis express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, ensure you have this project structure:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/token-blacklist
│
├── /config                   # Configuration files
│   └── redis-client.js       # Redis client configuration
│
├── /controllers              # Controllers handling requests and responses
│   └── logOutController.js   # Controller for logging out and blacklisting tokens
│
├── /middleware               # Middleware functions for request processing
│   └── authMiddleware.js     # Middleware for checking token validity and blacklisting
│
├── .env                      # Environment variables (Redis credentials, etc.)
├── package.json              # Project metadata and dependencies
├── package-lock.json         # Exact versions of installed dependencies
└── node_modules/             # Installed Node.js modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, set up environment variables in a &lt;code&gt;.env&lt;/code&gt; file to securely store the Redis credentials:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REDIS_HOST=redis-12345.c56.us-east-1–3.ec2.cloud.redislabs.com
REDIS_PORT=18285
REDIS_PASSWORD=your_secure_password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, configure the Redis client to connect to Redis Cloud in your config/redis-client.js file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const dotenv = require('dotenv');
const Redis = require('ioredis');

dotenv.config();

const redisClient = new Redis({
    host: process.env.REDIS_HOST,
    port: parseInt(process.env.REDIS_PORT),
    password: process.env.REDIS_PASSWORD,
});

redisClient.on('connect', () =&amp;gt; {
    console.log('Connected to Redis Cloud');
});

redisClient.on('error', (error) =&amp;gt; {
    console.error('Redis Client Error:', error);
});

// Optional: Test the connection to ensure it's working
redisClient
    .ping()
    .then((result) =&amp;gt; {
    console.log('Ping response:', result);
    })
    .catch((error) =&amp;gt; {
    console.error('Error pinging Redis:', error);
    });

module.exports =  redisClient;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explanation of Optional Logs&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Connect Log&lt;/strong&gt;: Prints to the console “Connected to Redis Cloud” when the Redis client successfully connects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error Log&lt;/strong&gt;: Logs any Redis connection errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ping&lt;/strong&gt; &lt;strong&gt;Test&lt;/strong&gt;: This step pings Redis on startup to confirm the connection is active. If successful, it logs the response; otherwise, it logs the error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Building the Blacklisting Controller
&lt;/h3&gt;

&lt;p&gt;Now, we’ll create our controller in thecontrollers/logoutContoller.js file to blacklist tokens. Upon logout, the token will be stored in Redis with a 5-minute expiration time (TTL), after which Redis automatically deletes it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const redisClient = require('../config/redis-client');

const LogOutController = async (req, res) =&amp;gt; {
    try {
        // Extract token from headers
        const token = req.headers.authorization?.split('Bearer ')[1];

        if (!token) {
          return res.status(401).json({ message: 'No token provided' });
        }

        // Blacklist the token with a TTL of 5 minutes (300 seconds)
        const ttl = 300; // 5 minutes in seconds
        await redisClient.setex(token, ttl, 'blacklisted');

        res.status(200).json({ message: 'Logout successful' });
   } catch (error) {
       console.error('Error in LogOutController:', error);
       res.status(500).json({ message: 'Could not blacklist token' });
   }
};

module.exports = LogOutController;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This controller simply takes the token from the request, and if provided, stores it in Redis with a TTL, effectively blacklisting it for a specified period.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Auth Middleware
&lt;/h3&gt;

&lt;p&gt;To secure routes, we’ll create a middleware/authMiddleware.js file that checks if a token is blacklisted. Any blacklisted token will immediately cause the middleware to block access.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const redisClient = require('../config/redis-client');

const authMiddleware = async (req, res, next) =&amp;gt; {
 try {
    const token = req.headers.authorization?.split('Bearer ')[1];

    if (!token) {
      return res.status(401).json({ message: 'No token provided' });
    }
    // Check if token is blacklisted
    const isBlacklisted = await redisClient.get(token);
    if (isBlacklisted) {
       return res.status(401).json({ message: 'Token has been blacklisted' });
    }
    // You can add token verifcation logic here
    next();
  } catch (error) {
     console.error('Authorization error:', error);
     res.status(500).json({ message: 'Authentication failed' });
  }
};

module.exports = authMiddleware;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Applying Token Blacklisting to Routes
&lt;/h3&gt;

&lt;p&gt;Here we ensure all routes with sensitive information are protected.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const authMiddleware = require('./middleware/authMiddleware');
const LogOutController = require('./controllers/logoutController');

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

// Public route
app.post('/logout', LogOutController);

// Protected route
app.get('/secure-data', authMiddleware, (req, res) =&amp;gt; {
    res.json({ message: 'This is secured data!' });
});

app.listen(3000, () =&amp;gt; {
    console.log('Server running on http://localhost:3000');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With Redis Cloud, we have an efficient, cloud-based token blacklisting system for token-based authentication. By storing tokens with a TTL, we ensure they expire without manual cleanup, and our middleware ensures that blacklisted tokens are denied access, keeping our system secure.&lt;/p&gt;

&lt;p&gt;With this setup, you’ve created a secure and scalable token blacklisting solution using Redis Cloud in Node.js.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
