PHPackages                             tenantwave/broadcast - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. tenantwave/broadcast

ActiveLibrary[API Development](/categories/api)

tenantwave/broadcast
====================

Tenant-aware broadcasting for shared database multi-tenancy in Laravel

20PHP

Since Feb 4Pushed 3mo agoCompare

[ Source](https://github.com/abdi2332/tenancy-broadcast)[ Packagist](https://packagist.org/packages/tenantwave/broadcast)[ RSS](/packages/tenantwave-broadcast/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

Laravel Tenant Broadcast
========================

[](#laravel-tenant-broadcast)

A lightweight, opinionated package for securing real-time broadcasting in **single shared database** multi-tenant applications.

This package automatically scopes broadcast channels by tenant ID and enforces strict authorization checks, preventing cross-tenant data leaks in Laravel Reverb, Pusher, or other broadcasting drivers.

**Designed specifically for shared database multi-tenancy** where all tenants share a single database and tenancy is determined by a column on the `users` table (e.g., `tenant_id`). This is **not** for multi-database tenancy modular architectures.

Features
--------

[](#features)

- **Automatic Channel Scoping**: Automatically converts logical channel names (e.g., `orders`) into tenant-scoped channels (e.g., `tenant.1.orders`).
- **Strict Authorization**: Enforces tenant access controls at the routing level, ensuring users can only subscribe to channels belonging to their tenant.
- **Background Broadcasting**: Supports broadcasting from background jobs, queues, and system commands where no user is authenticated.
- **Zero Heavy Dependencies**: Does not require complex multi-tenancy frameworks.

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 10.0+ or 11.0+

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require tenantwave/broadcast
```

Publish the configuration file:

```
php artisan vendor:publish --tag=tenant-broadcast-config
```

Configuration
-------------

[](#configuration)

Configure the package in `config/tenant-broadcast.php` or via your `.env` file.

```
# Enable or disable the package
TENANT_BROADCAST_ENABLED=true

# The column on your User model that stores the tenant ID
TENANT_BROADCAST_KEY=tenant_id

# The prefix pattern for tenant-scoped channels (use {id} as placeholder)
TENANT_BROADCAST_PREFIX=tenant.{id}.

# Strict mode: throw exceptions if tenant context cannot be resolved
TENANT_BROADCAST_STRICT=true
```

Usage
-----

[](#usage)

### 1. Broadcasting Events

[](#1-broadcasting-events)

In your Event classes, use the `TenantBroadcast` facade instead of `PrivateChannel`.

```
use RealtimeKit\TenantBroadcast\Facades\TenantBroadcast;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class OrderUpdated implements ShouldBroadcast
{
    public function __construct(
        public Order $order
    ) {}

    public function broadcastOn(): array
    {
        // Automatically scopes to: private-tenant.{tenant_id}.orders
        return [
            TenantBroadcast::channel('orders')
        ];
    }
}
```

### 2. Authorizing Channels

[](#2-authorizing-channels)

Register your channel routes in `routes/channels.php` using the `TenantBroadcast::route` method. This automatically applies the tenant authorization guard before your callback runs.

```
use RealtimeKit\TenantBroadcast\Facades\TenantBroadcast;

// registers: tenant.{tenant_id}.orders
TenantBroadcast::route('orders', function ($user, $orderId) {
    // This callback ONLY executes if $user->tenant_id matches the channel's tenant ID.
    // You can now safely focus on resource authorization.
    return $user->can('view', Order::find($orderId));
});
```

### 3. Client-Side (Laravel Echo)

[](#3-client-side-laravel-echo)

Your frontend application must subscribe to the full, tenant-scoped channel name.

```
// Assuming you pass the user's tenant ID to your frontend
const tenantId = user.tenant_id;

Echo.private(`tenant.${tenantId}.orders`)
    .listen('OrderUpdated', (e) => {
        console.log(e.order);
    });
```

Advanced Usage
--------------

[](#advanced-usage)

### Background Jobs &amp; Queues

[](#background-jobs--queues)

When broadcasting from a Job or Queue, there is no authenticated user. You must provide the tenant context explicitly.

**Option 1: Explicit Tenant ID**

Pass the tenant ID as the second argument to `channel`.

```
public function handle()
{
    $order = Order::find($this->orderId);

    broadcast(new OrderUpdated($order))->to(
        TenantBroadcast::channel('orders', $order->tenant_id)
    );
}
```

**Option 2: Context Impersonation**

If you need to broadcast multiple events or use existing logic that relies on implicit resolution, you can "impersonate" a tenant context.

```
use RealtimeKit\TenantBroadcast\TenantResolver;

public function handle(TenantResolver $resolver)
{
    $resolver->impersonate($this->tenantId);

    // This will now use the impersonated tenant ID automatically
    // broadcast(new OrderUpdated($this->order));

    $resolver->forget();
}
```

Security
--------

[](#security)

This package operates in **Strict Mode** by default.

If `TenantBroadcast::channel()` is called without an authenticated user and without an explicit tenant ID (or impersonation context), it will throw a `RuntimeException`. This prevents accidental broadcasting to global or undefined channels.

License
-------

[](#license)

The MIT License (MIT). Please see License File for more information.

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance54

Moderate activity, may be stable

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity12

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/b15ad39c34cb17beccb95d111114ed454f8f0875ac958b8398d9ab06f6269052?d=identicon)[abdi2332](/maintainers/abdi2332)

---

Top Contributors

[![abdi2332](https://avatars.githubusercontent.com/u/101140054?v=4)](https://github.com/abdi2332 "abdi2332 (14 commits)")

### Embed Badge

![Health badge](/badges/tenantwave-broadcast/health.svg)

```
[![Health](https://phpackages.com/badges/tenantwave-broadcast/health.svg)](https://phpackages.com/packages/tenantwave-broadcast)
```

###  Alternatives

[stripe/stripe-php

Stripe PHP Library

4.0k143.3M480](/packages/stripe-stripe-php)[twilio/sdk

A PHP wrapper for Twilio's API

1.6k92.9M272](/packages/twilio-sdk)[facebook/php-business-sdk

PHP SDK for Facebook Business

90821.9M34](/packages/facebook-php-business-sdk)[meilisearch/meilisearch-php

PHP wrapper for the Meilisearch API

74513.7M114](/packages/meilisearch-meilisearch-php)[google/gax

Google API Core for PHP

265103.1M454](/packages/google-gax)[google/common-protos

Google API Common Protos for PHP

173103.7M50](/packages/google-common-protos)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
