cd..blog

Real-Time Microservices: Moleculer, Cloudflare & Secure WebSockets

const published = "Nov 20, 2025, 10:21 PM";const readTime = 4 min;
moleculercloudflarewebsocketstypescriptmicroservices
Explore integrating Moleculer microservices with Cloudflare for secure, real-time WebSocket applications. Learn about authentication, authorization, and best practices in TypeScript.

Building Secure, Real-Time Microservices with Moleculer, Cloudflare, and TypeScript

Modern web applications demand high scalability, real-time interactions, and robust security. Integrating a microservices framework like Moleculer with a global network like Cloudflare provides a powerful stack for achieving these goals, especially when combined with secure authentication and real-time WebSockets. This post demonstrates how to weave these technologies into a cohesive, TypeScript-driven application.

Architecture Overview

Our architecture centers around Moleculer microservices handling business logic and real-time events. Cloudflare acts as a protective shield and performance enhancer, proxying all traffic, including WebSockets, to our backend. Authentication and authorization secure access, while WebSockets facilitate instant communication.

Moleculer Microservices with TypeScript

Moleculer is a fast, modern, and powerful microservices framework for Node.js, providing features like service discovery, load balancing, and event-driven communication. We'll use TypeScript for type safety and enhanced developer experience.

// services/users.service.ts
import { Service, ServiceBroker } from "moleculer";

interface User { id: string; username: string; email: string; }
interface AuthenticatedUser { userId: string; username: string; token: string; }

export default class UsersService extends Service {
  public constructor(broker: ServiceBroker) {
    super(broker);
    this.parseServiceSchema({
      name: "users",
      actions: {
        // Authenticate a user and return a JWT token
        login: {
          params: {
            username: "string",
            password: "string",
          },
          async handler(ctx): Promise<AuthenticatedUser | null> {
            // In a real app, validate credentials against a DB
            const { username, password } = ctx.params;
            if (username === "admin" && password === "password") {
              const token = await this.broker.call("auth.generateToken", { userId: "123", roles: ["admin"] });
              return { userId: "123", username, token };
            }
            return null;
          },
        },
        // Get user profile (requires authentication)
        profile: {
          auth: "required", // Custom metadata for auth middleware
          async handler(ctx): Promise<User> {
            const { userId } = ctx.meta.user; // User from auth middleware
            // Fetch user data from DB
            return { id: userId, username: "admin", email: "admin@example.com" };
          },
        },
      },
      events: {
        "user.created": {
          handler(ctx) {
            this.logger.info(`New user created: ${ctx.params.username}`);
          },
        },
      },
    });
  }
}

The users service handles user-related actions, including a login action to simulate authentication and a profile action requiring authorization.

Authentication & Authorization

We implement JWT-based authentication using a dedicated auth service and Moleculer middleware for validation. Authorization is handled via role-based access control (RBAC) within service actions.

// services/auth.service.ts
import { Service, ServiceBroker } from "moleculer";
import * as jwt from "jsonwebtoken";

const JWT_SECRET = process.env.JWT_SECRET || "super-secret-key";

export default class AuthService extends Service {
  public constructor(broker: ServiceBroker) {
    super(broker);
    this.parseServiceSchema({
      name: "auth",
      actions: {
        generateToken: {
          params: {
            userId: "string",
            roles: { type: "array", items: "string", optional: true, default: [] },
          },
          handler(ctx): string {
            return jwt.sign({ userId: ctx.params.userId, roles: ctx.params.roles }, JWT_SECRET, { expiresIn: "1h" });
          },
        },
        verifyToken: {
          params: {
            token: "string",
          },
          handler(ctx): any {
            try {
              return jwt.verify(ctx.params.token, JWT_SECRET);
            } catch (error: any) {
              this.logger.warn("Invalid JWT token:", error.message);
              throw new Error("Invalid Token");
            }
          },
        },
      },
    });
  }
}

// src/middlewares/auth.middleware.ts
import { Context, Middleware, ServiceBroker } from "moleculer";

export const AuthMiddleware = (broker: ServiceBroker): Middleware => {
  return {
    async call(next, action) {
      // Check for custom 'auth' metadata on the action
      if (action.auth === "required") {
        const token = action.ctx.meta.token; // Assume token is passed in meta from API Gateway
        if (!token) {
          throw new Error("Authentication required.");
        }
        try {
          const decoded = await broker.call("auth.verifyToken", { token });
          action.ctx.meta.user = decoded; // Attach decoded user info to context
        } catch (error) {
          throw new Error("Invalid or expired token.");
        }
      }
      return next(action);
    },
  };
};

The AuthMiddleware intercepts service calls, validates the JWT, and attaches user information to the context for subsequent authorization checks.

Real-Time WebSockets with moleculer-io

moleculer-io seamlessly integrates Socket.IO with Moleculer, enabling real-time communication across your microservices. We'll use it to broadcast chat messages.

// services/chat.service.ts
import { Service, ServiceBroker } from "moleculer";
import { IoService } from "moleculer-io"; // Import IoService from moleculer-io

export default class ChatService extends Service {
  public constructor(broker: ServiceBroker) {
    super(broker);
    this.parseServiceSchema({
      name: "chat",
      mixins: [IoService], // Mixin IoService to enable WebSocket features
      settings: {
        io: {
          namespaces: {
            "/": {
              // Middleware for Socket.IO connection authentication
              middlewares: [
                async (socket, next) => {
                  const token = socket.handshake.query.token as string;
                  if (!token) {
                    return next(new Error("Authentication required for WebSocket."));
                  }
                  try {
                    const decoded = await this.broker.call("auth.verifyToken", { token });
                    socket.data.user = decoded; // Attach user info to socket
                    next();
                  } catch (error) {
                    next(new Error("Invalid WebSocket token."));
                  }
                },
              ],
              events: {
                // Handle incoming 'message' event from client
                message: {
                  // Custom auth for Socket.IO event handler (can be extended)
                  handler(socket, payload: { text: string }) {
                    const { user } = socket.data;
                    this.logger.info(`User ${user.userId} sent message: ${payload.text}`);
                    // Broadcast message to all connected clients in this namespace
                    this.io.of("/").emit("message", {
                      userId: user.userId,
                      text: payload.text,
                      timestamp: Date.now(),
                    });
                  },
                },
              },
            },
          },
        },
      },
      actions: {
        // Example action to send a server-initiated message
        sendMessageToAll: {
          params: {
            text: "string",
          },
          handler(ctx) {
            this.io.of("/").emit("serverMessage", { text: ctx.params.text, timestamp: Date.now() });
            return true;
          },
        },
      },
    });
  }
}

The chat service uses IoService to manage Socket.IO connections and events, including an authentication middleware for WebSocket connections and an event handler for broadcasting messages.

Cloudflare Integration

Cloudflare provides a global network that enhances performance, security, and reliability. By proxying your domain through Cloudflare, it automatically handles DDoS protection, WAF, and SSL/TLS termination, including for WebSockets (wss://).

  1. DNS Configuration: Point your domain's A or CNAME record to your Moleculer API Gateway's public IP/hostname, ensuring the "Proxy status" is "Proxied" (orange cloud).
  2. WebSocket Proxying: Cloudflare automatically proxies WebSocket traffic (port 80/443) when HTTP proxying is enabled. No special configuration is usually needed for standard wss:// connections.
  3. Security Rules: Leverage Cloudflare's Web Application Firewall (WAF) to add custom rules for protecting your API endpoints and mitigating common web vulnerabilities.
  4. Rate Limiting: Implement Cloudflare rate limiting rules to prevent abuse of your API and WebSocket connections.

Cloudflare sits in front of your Moleculer API Gateway (likely using moleculer-web with moleculer-io attached), handling all incoming requests and securing them before they reach your infrastructure.

Conclusion

By integrating Moleculer microservices with Cloudflare, secure authentication, and real-time WebSockets, you build a robust, scalable, and performant application. This architecture provides modularity, enhanced security, and a seamless real-time experience for users, all powered by TypeScript. Embrace these tools to deliver the next generation of web applications.