Overview
WireChat includes built-in middleware for panel access control, conversation authorization, and route protection. You can also add custom middleware to implement additional security or business logic.
Built-in Middleware
WireChat provides three core middleware classes:
SetCurrentPanel
Sets the active panel for the current request.
src/Middleware/SetCurrentPanel.php
namespace Wirechat\Wirechat\Middleware ;
use Closure ;
use Illuminate\Http\ Request ;
class SetCurrentPanel
{
public function handle ( Request $request , Closure $next , string $panelId )
{
app ( \Wirechat\Wirechat\ PanelRegistry :: class ) -> setCurrent ( $panelId );
return $next ( $request );
}
}
This middleware is automatically applied to all WireChat routes and should not be removed.
EnsureWirechatPanelAccess
Verifies that the authenticated user has permission to access a specific panel.
src/Middleware/EnsureWirechatPanelAccess.php
namespace Wirechat\Wirechat\Middleware ;
use Closure ;
use Illuminate\Support\Facades\ Auth ;
use Wirechat\Wirechat\ PanelRegistry ;
class EnsureWirechatPanelAccess
{
public function handle ( $request , Closure $next , string $panelId )
{
$panel = app ( PanelRegistry :: class ) -> get ( $panelId );
if ( ! $panel ) {
abort ( 404 , 'Panel not found.' );
}
$user = Auth :: user ();
if ( ! $user || ! $user -> canAccessWirechatPanel ( $panel )) {
abort ( 404 );
}
return $next ( $request );
}
}
Implementing Panel Access Control
Add the canAccessWirechatPanel method to your User model:
Basic Access
Role-Based Access
Panel-Specific Access
use Wirechat\Wirechat\ Panel ;
public function canAccessWirechatPanel ( Panel $panel ) : bool
{
// All authenticated users can access
return true ;
}
use Wirechat\Wirechat\ Panel ;
public function canAccessWirechatPanel ( Panel $panel ) : bool
{
// Only users with 'chat' permission
return $this -> can ( 'access-chat' );
}
use Wirechat\Wirechat\ Panel ;
public function canAccessWirechatPanel ( Panel $panel ) : bool
{
return match ( $panel -> getId ()) {
'admin' => $this -> isAdmin (),
'support' => $this -> hasRole ([ 'support' , 'admin' ]),
'default' => true ,
default => false ,
};
}
BelongsToConversation
Ensures the authenticated user is a participant in the requested conversation.
src/Middleware/BelongsToConversation.php
namespace Wirechat\Wirechat\Middleware ;
use Closure ;
use Illuminate\Http\ Request ;
use Wirechat\Wirechat\Models\ Conversation ;
class BelongsToConversation
{
public function handle ( Request $request , Closure $next )
{
$user = $request -> user ();
$conversationId = $request -> route ( 'conversation' );
$conversation = Conversation :: findOrFail ( $conversationId );
if ( ! $user || ! $user -> belongsToConversation ( $conversation )) {
abort ( 403 , 'Forbidden' );
}
return $next ( $request );
}
}
Implementing Conversation Authorization
Add the belongsToConversation method to your User model:
use Wirechat\Wirechat\Models\ Conversation ;
use Wirechat\Wirechat\Concerns\ Chats ;
class User extends Authenticatable
{
use Chats ;
public function belongsToConversation ( Conversation $conversation ) : bool
{
return $this -> conversations ()
-> where ( 'conversations.id' , $conversation -> id )
-> exists ();
}
}
Custom Middleware
Adding Middleware to Routes
Configure global middleware for all WireChat routes:
app/Providers/WirechatServiceProvider.php
use Wirechat\Wirechat\ Panel ;
Panel :: make ()
-> middleware ([
'web' ,
'auth' ,
\App\Http\Middleware\ VerifyEmailAddress :: class ,
]);
Chat-Specific Middleware
Add middleware only to chat conversation routes:
Panel :: make ()
-> chatMiddleware ([
\App\Http\Middleware\ LogChatActivity :: class ,
\App\Http\Middleware\ CheckChatSubscription :: class ,
]);
Chat middleware is applied in addition to global panel middleware.
Example Custom Middleware
Rate Limiting
app/Http/Middleware/RateLimitChat.php
namespace App\Http\Middleware ;
use Closure ;
use Illuminate\Http\ Request ;
use Illuminate\Support\Facades\ RateLimiter ;
class RateLimitChat
{
public function handle ( Request $request , Closure $next )
{
$key = 'chat-access:' . $request -> user () -> id ;
if ( RateLimiter :: tooManyAttempts ( $key , 100 )) {
return response () -> json ([
'message' => 'Too many requests. Please slow down.'
], 429 );
}
RateLimiter :: hit ( $key , 60 );
return $next ( $request );
}
}
Activity Logging
app/Http/Middleware/LogChatActivity.php
namespace App\Http\Middleware ;
use Closure ;
use Illuminate\Http\ Request ;
use Illuminate\Support\Facades\ Log ;
class LogChatActivity
{
public function handle ( Request $request , Closure $next )
{
$user = $request -> user ();
$conversationId = $request -> route ( 'conversation' );
if ( $conversationId ) {
Log :: info ( 'Chat access' , [
'user_id' => $user -> id ,
'conversation_id' => $conversationId ,
'ip' => $request -> ip (),
'user_agent' => $request -> userAgent (),
]);
}
return $next ( $request );
}
}
Subscription Check
app/Http/Middleware/CheckChatSubscription.php
namespace App\Http\Middleware ;
use Closure ;
use Illuminate\Http\ Request ;
class CheckChatSubscription
{
public function handle ( Request $request , Closure $next )
{
$user = $request -> user ();
if ( ! $user -> hasActiveSubscription ()) {
return redirect () -> route ( 'subscription.required' )
-> with ( 'error' , 'Please upgrade your plan to access chat.' );
}
return $next ( $request );
}
}
Content Moderation
app/Http/Middleware/ContentModeration.php
namespace App\Http\Middleware ;
use Closure ;
use Illuminate\Http\ Request ;
class ContentModeration
{
public function handle ( Request $request , Closure $next )
{
$user = $request -> user ();
// Check if user is banned or muted
if ( $user -> isBannedFromChat ()) {
abort ( 403 , 'You have been banned from chat.' );
}
if ( $user -> isMuted () && $request -> isMethod ( 'post' )) {
abort ( 403 , 'You are temporarily muted.' );
}
return $next ( $request );
}
}
Middleware Configuration
Panel-Level Middleware
app/Providers/WirechatServiceProvider.php
use Wirechat\Wirechat\ Panel ;
// Admin panel with strict middleware
Panel :: make ()
-> id ( 'admin' )
-> middleware ([
'web' ,
'auth' ,
\App\Http\Middleware\ MustBeAdmin :: class ,
]);
// Customer support panel
Panel :: make ()
-> id ( 'support' )
-> middleware ([
'web' ,
'auth' ,
\App\Http\Middleware\ MustBeSupportAgent :: class ,
])
-> chatMiddleware ([
\App\Http\Middleware\ LogSupportActivity :: class ,
]);
// Public user panel
Panel :: make ()
-> id ( 'default' )
-> middleware ([
'web' ,
'auth' ,
])
-> chatMiddleware ([
\App\Http\Middleware\ CheckChatSubscription :: class ,
]);
Authentication Guards
Using Custom Guards
If you’re using custom authentication guards:
app/Providers/WirechatServiceProvider.php
Panel :: make ()
-> authGuard ( 'admin' )
-> middleware ([
'web' ,
'auth:admin' ,
]);
Multiple Guards
Panel :: make ()
-> id ( 'multi-auth' )
-> middleware ([
'web' ,
'auth:web,api' ,
]);
Middleware Execution Order
Middleware is executed in this order:
Global Middleware
Laravel’s global middleware from app/Http/Kernel.php
Panel Middleware
Middleware configured via Panel::middleware()
WireChat Core Middleware
SetCurrentPanel
EnsureWirechatPanelAccess
Chat Middleware
Middleware configured via Panel::chatMiddleware() (chat routes only)
BelongsToConversation (conversation routes only)
Testing Middleware
Feature Test Example
tests/Feature/ChatAccessTest.php
namespace Tests\Feature ;
use Tests\ TestCase ;
use App\Models\ User ;
use Wirechat\Wirechat\Models\ Conversation ;
class ChatAccessTest extends TestCase
{
public function test_user_can_access_own_conversation ()
{
$user = User :: factory () -> create ();
$conversation = Conversation :: factory () -> create ();
$conversation -> addParticipant ( $user );
$this -> actingAs ( $user )
-> get ( route ( 'wirechat.chat' , $conversation -> id ))
-> assertOk ();
}
public function test_user_cannot_access_other_conversation ()
{
$user = User :: factory () -> create ();
$otherConversation = Conversation :: factory () -> create ();
$this -> actingAs ( $user )
-> get ( route ( 'wirechat.chat' , $otherConversation -> id ))
-> assertForbidden ();
}
public function test_guest_cannot_access_chat ()
{
$conversation = Conversation :: factory () -> create ();
$this -> get ( route ( 'wirechat.chat' , $conversation -> id ))
-> assertRedirect ( route ( 'login' ));
}
}
Best Practices
Always verify user authorization at both the middleware and component level
Use rate limiting to prevent abuse
Log important chat activities for audit trails
Keep middleware focused on a single responsibility
Test middleware thoroughly with different user roles
Next Steps
Actions Configure chat and group actions
Broadcasting Set up real-time events