Skip to content
Back to skills

Centrifugo

ASecurity

Centrifugo real-time messaging server expert for WebSocket PUB/SUB, channel management, JWT authentication, event proxying, and horizontal scaling with Redis/NATS. Use when: centrifugo, centrifugal, real-time messaging, websocket pubsub, channel subscriptions, real-time notifications, live updates, presence, history recovery, server-sent events integration, real-time transport layer. Do not use for: general WebSocket programming without Centrifugo, Socket.IO, Pusher SDK, or other real-time fr...

  • 617 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 5, 2026
developmentjavascriptpythongojavaphpswiftbashreactnodeexpress

Works with

  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 8 files and shows the line behind each finding

Scanned June 5, 2026

npx -y skills add pedronauck/skills --skill centrifugo --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Centrifugo?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Centrifugo
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/pedronauck-centrifugo/badge)](https://www.skillsdirectory.com/skills/pedronauck-centrifugo)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: centrifugo
description: "Centrifugo real-time messaging server expert for WebSocket PUB/SUB, channel management, JWT authentication, event proxying, and horizontal scaling with Redis/NATS. Use when: centrifugo, centrifugal, real-time messaging, websocket pubsub, channel subscriptions, real-time notifications, live updates, presence, history recovery, server-sent events integration, real-time transport layer. Do not use for: general WebSocket programming without Centrifugo, Socket.IO, Pusher SDK, or other real-time frameworks."
---

# Centrifugo Real-Time Messaging Integration

Centrifugo is a self-hosted, language-agnostic real-time messaging server. It handles persistent connections (WebSocket, SSE, HTTP-streaming, WebTransport, GRPC) and broadcasts messages via a channel-based PUB/SUB model. The application backend publishes to channels via Server API; Centrifugo delivers to online subscribers instantly.

## Core Architecture

```
Backend App ──(HTTP/GRPC Server API)──> Centrifugo Cluster ──(WebSocket/SSE)──> Clients
                                              │
                                        Redis/NATS Broker
                                        (for multi-node)
```

**Key principle**: All user-generated data flows through the application backend first (validate, persist, then publish to Centrifugo). Centrifugo is the transport layer, not the source of truth.

## Procedures

### Step 1: Determine Integration Pattern

Identify the real-time feature being built and select the appropriate pattern:

1. **Unidirectional publish** (most common): Backend publishes to channels after processing user requests. Clients subscribe and receive updates passively.
2. **Bidirectional with proxy**: Clients send data over the real-time connection; Centrifugo proxies events (connect, subscribe, publish, RPC) to the backend for validation.
3. **Server-side subscriptions**: Backend controls which channels a user subscribes to (useful for personalized feeds, notifications).

### Step 2: Configure Centrifugo Server

Generate a minimal configuration:

```bash
centrifugo genconfig  # Creates config.json
```

Or use Docker:

```bash
docker run -p 8000:8000 centrifugo/centrifugo:v6 centrifugo
```

Essential configuration structure (JSON, YAML, or TOML supported):

```json
{
  "client": {
    "token": {
      "hmac_secret_key": "<SECRET>"
    },
    "allowed_origins": ["http://localhost:3000"]
  },
  "http_api": {
    "key": "<API_KEY>"
  },
  "channel": {
    "without_namespace": {
      "allow_subscribe_for_client": true
    }
  }
}
```

Read `references/configuration.md` for the full configuration reference including TLS, admin UI, environment variables, and advanced options.

### Step 3: Set Up Authentication

Centrifugo authenticates clients via JWT or connect proxy.

**JWT approach** (recommended for most cases):

- Backend generates a JWT with `sub` (user ID) and `exp` claims, signed with the configured HMAC/RSA/ECDSA key.
- Client passes the token when connecting.
- Supports token refresh for long-lived connections.

```python
# Backend: generate connection JWT (Python example)
import jwt, time
token = jwt.encode(
    {"sub": "user123", "exp": int(time.time()) + 3600},
    "<HMAC_SECRET>", algorithm="HS256"
)
```

```javascript
// Client: connect with token
const client = new Centrifuge("ws://localhost:8000/connection/websocket", {
  token: "<JWT_TOKEN>",
});
client.connect();
```

**Connect proxy approach** (alternative):

- Centrifugo forwards connection requests to the backend endpoint for authentication.
- No JWT needed; backend responds with user identity.

Read `references/authentication.md` for JWT claims, token refresh, proxy auth, and channel-level authorization tokens.

### Step 4: Design Channel Structure

Channels are ephemeral strings that serve as message pathways. Use namespaces to apply different behaviors.

**Naming conventions**:

- `chat:room-123` — namespace `chat`, channel for room 123
- `notifications:user#42` — user-limited channel (only user 42 can subscribe)
- `$private:secret` — private channel prefix (requires subscription token)

**Namespace configuration**:

```json
{
  "channel": {
    "namespaces": [
      {
        "name": "chat",
        "presence": true,
        "history_size": 50,
        "history_ttl": "300s",
        "force_recovery": true,
        "join_leave": true
      },
      {
        "name": "notifications",
        "allow_user_limited_channels": true
      }
    ]
  }
}
```

Read `references/channels.md` for all channel options, namespace rules, and special channel prefixes.

### Step 5: Publish from Backend (Server API)

Use HTTP or GRPC to publish messages from the application backend.

**HTTP API** — POST to `/api/<method>` with `X-API-Key` header:

```bash
# Publish to a channel
curl -X POST -H "X-API-Key: <KEY>" -H "Content-Type: application/json" \
  -d '{"channel": "chat:room-1", "data": {"text": "hello"}}' \
  http://localhost:8000/api/publish

# Broadcast to multiple channels
curl -X POST -H "X-API-Key: <KEY>" -H "Content-Type: application/json" \
  -d '{"channels": ["user:1", "user:2"], "data": {"text": "hello"}}' \
  http://localhost:8000/api/broadcast
```

**Available API methods**: `publish`, `broadcast`, `subscribe`, `unsubscribe`, `disconnect`, `refresh`, `presence`, `presence_stats`, `history`, `history_remove`, `channels`, `info`, `batch`.

Read `references/server-api.md` for all method signatures, request/response schemas, and HTTP API library links.

### Step 6: Connect Clients with SDK

Official SDKs: `centrifuge-js` (browser/Node/React Native), `centrifuge-go`, `centrifuge-dart` (Flutter), `centrifuge-swift` (iOS), `centrifuge-java` (Android), `centrifuge-python`.

**JavaScript client pattern**:

```javascript
import { Centrifuge } from "centrifuge";

const client = new Centrifuge("ws://localhost:8000/connection/websocket", {
  token: "<JWT>",
});

// Connection state handlers
client.on("connecting", ctx => console.log("connecting", ctx));
client.on("connected", ctx => console.log("connected", ctx));
client.on("disconnected", ctx => console.log("disconnected", ctx));

// Subscribe to channel
const sub = client.newSubscription("chat:room-1");
sub.on("publication", ctx => {
  console.log("received:", ctx.data);
});
sub.on("subscribing", ctx => console.log("subscribing", ctx));
sub.on("subscribed", ctx => console.log("subscribed", ctx));
sub.subscribe();

client.connect();
```

**Client states**: `disconnected` -> `connecting` -> `connected` (auto-reconnect with exponential backoff).

**Subscription states**: `unsubscribed` -> `subscribing` -> `subscribed` (auto-resubscribe on reconnect).

Read `references/client-sdk.md` for all SDK patterns, token refresh, presence/history from client, RPC calls, and Protobuf mode.

### Step 7: Configure Event Proxy (Optional)

Proxy client events to the backend for validation and custom logic.

**Supported proxy events**:

- `connect` — authenticate connections without JWT
- `refresh` — extend client sessions
- `subscribe` — validate channel access
- `publish` — validate publications from clients
- `rpc` — handle custom client-to-server calls
- `sub_refresh` — extend subscription sessions

```json
{
  "client": {
    "proxy": {
      "connect": {
        "enabled": true,
        "endpoint": "http://backend:3000/centrifugo/connect"
      },
      "rpc": {
        "enabled": true,
        "endpoint": "http://backend:3000/centrifugo/rpc"
      }
    }
  },
  "channel": {
    "namespaces": [
      {
        "name": "chat",
        "proxy": {
          "subscribe": {
            "enabled": true,
            "endpoint": "http://backend:3000/centrifugo/subscribe"
          },
          "publish": {
            "enabled": true,
            "endpoint": "http://backend:3000/centrifugo/publish"
          }
        }
      }
    ]
  }
}
```

Read `references/proxy.md` for proxy request/response schemas, GRPC proxy, header forwarding, and timeout configuration.

### Step 8: Scale Horizontally (Production)

**Memory engine** (default): Single node only. Fast, no dependencies. Suitable for development and small deployments.

**Redis engine**: Multi-node clusters. Messages published on any node reach all subscribers.

```json
{
  "engine": {
    "type": "redis",
    "redis": {
      "address": "redis://localhost:6379"
    }
  }
}
```

Supports Redis Sentinel, Redis Cluster, consistent sharding across multiple Redis instances, and Redis-compatible storages (Valkey, DragonflyDB, KeyDB, AWS ElastiCache).

**NATS broker**: Alternative for PUB/SUB only (no history/presence persistence).

Read `references/engines.md` for Redis Sentinel/Cluster setup, sharding, NATS configuration, and separate broker/presence manager configuration.

### Step 9: Enable History and Recovery

History allows caching recent publications per channel. Recovery automatically restores missed messages after reconnection.

```json
{
  "channel": {
    "namespaces": [
      {
        "name": "chat",
        "history_size": 100,
        "history_ttl": "600s",
        "force_recovery": true,
        "force_positioning": true
      }
    ]
  }
}
```

- `history_size` + `history_ttl`: Define retention window.
- `force_recovery`: Clients automatically recover missed messages on reconnect.
- `force_positioning`: Detect publication gaps.
- **Cache recovery mode**: Optimized for channels where only the latest state matters. Read `references/channels.md` for details.

### Step 10: Add Observability

Centrifugo exposes Prometheus metrics at `/metrics` and supports structured logging.

```json
{
  "log_level": "info",
  "prometheus": {
    "enabled": true
  },
  "health": {
    "enabled": true
  }
}
```

Metrics include: connections, subscriptions, publications, API calls, transport stats, and engine stats.

## Anti-Patterns

### Do NOT use Centrifugo history as a primary database

History is an ephemeral hot cache designed to reduce database load during reconnect storms. Always maintain a primary application database.

### Do NOT rely solely on Centrifugo for data delivery

Design with graceful degradation. If Centrifugo goes down, the application should still function (just without real-time updates). Return data in API responses, not only via channels.

### Do NOT skip `allowed_origins` in production

Empty `allowed_origins` blocks all browser connections. Configure it with the exact origins of the frontend application.

### Do NOT publish directly from clients without proxy validation

Always validate client publications through either:

- The application backend (clients call backend API, backend publishes to Centrifugo), or
- Publish proxy (Centrifugo forwards client publish to backend for validation)

### Do NOT use channels without namespaces in production

Namespaces provide granular control over channel behavior and permissions. Define a namespace for each real-time feature.

### Do NOT ignore token expiration

Set reasonable `exp` claims in JWTs. Too short = excessive refresh requests. Too long = delayed user deactivation. Implement the token refresh callback in client SDKs.

## Error Handling

- If the client receives `102: unknown channel` — verify the namespace is defined in configuration.
- If the client receives `103: permission denied` — check channel permissions (`allow_subscribe_for_client`, subscription JWT, or subscribe proxy).
- If publications are not delivered — verify the channel name matches exactly (namespace prefix included). Ensure at least one subscriber exists.
- If reconnection loops occur — check `allowed_origins`, JWT validity/expiration, and network connectivity.
- If Redis engine fails to connect — verify address format (`redis://`, `rediss://` for TLS, `redis+sentinel://` for Sentinel, `redis+cluster://` for Cluster).

## Related Integrations

Centrifugo integrates well with any backend language/framework. Common setups include:

- **Node.js/Hono/Express**: Use HTTP API or `centrifuge` npm package for server-side operations.
- **Go**: Use the `centrifuge` Go library directly or the Centrifugo HTTP/GRPC API.
- **Python/Django/Flask**: Use `pycent` library or direct HTTP API calls.
- **PHP/Laravel**: Use `phpcent` library.

For the JavaScript client SDK (`centrifuge-js`), install via npm:

```bash
npm install centrifuge
# or
bun add centrifuge
```

Files in this skill

  • SKILL.md12.1 KB
  • references/authentication.md5.1 KB
  • references/channels.md5.8 KB
  • references/client-sdk.md6.2 KB
  • references/configuration.md5 KB
  • references/engines.md4.4 KB
  • references/proxy.md5.7 KB
  • references/server-api.md7.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.