beyondcode / laravel-websockets

Websockets for Laravel. Done right.
https://beyondco.de/docs/laravel-websockets
MIT License
5.07k stars 612 forks source link

SSL certificate problem: unable to get local issuer certificate (with new information) #879

Closed vesper8 closed 7 months ago

vesper8 commented 2 years ago

On my dev environment (Mac) I used to be able to use laravel-websockets without any issues. Recently after running some updates things stopped working and I am now getting the

SSL certificate problem: unable to get local issuer certificate error.

I've been trying to troubleshoot this issue and found a lot of new information which doesn't seem to be mentioned on the multiple other SSL threads so I thought I would share here to help us all come to an answer.

864 #845 #815 #792 #760 #753 #743 #732 #680

First of all, it should be noted that curl_options was deprecated as of 6.0.0 of pusher/pusher-php-server.

https://github.com/pusher/pusher-http-php/blob/master/CHANGELOG.md

I checked my version and I'm on 7.0.1. This is on the project doing the broadcasting. On the project hosting the laravel-websockets package it's on 5.0.3

So all solutions pointing to the "old way" of circumventing this issue by using, provided you're using ^6.0

    'curl_options' => [
        CURLOPT_SSL_VERIFYHOST => 0,
        CURLOPT_SSL_VERIFYPEER => 0,
    ],

... are now obsolete

In debugging the issue, I noticed that if I modify this file vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php and add

$options['verify'] = false;

inside the __invoke method.

Then the problem goes away.

The only remaining issue now is that I'm at a loss of how to set this verify=false in any of the configuration files.

Even though pusher has deprecated curl_options, I can't find any information yet on how we are supposed to disable verification following this deprecation.

Hopefully this new information leads us to answer as I see many people struggling with this issue right now

vesper8 commented 2 years ago

I should add that downgrading pusher/pusher-php-server from ^7.0 to ^5.0 on the project doing the broadcasting also makes this error go away, since this version does support curl_options

vesper8 commented 2 years ago

I opened an issue on pusher/pusher-php-server and quickly received an answer that there is no workaround

https://github.com/pusher/pusher-http-php/issues/313#issuecomment-953829917

I guess forking Guzzle itself and adding an optional configuration to allow for slipping in $options['verify'] = false; in there is a possible workaround

For now it seems like reverting to ^5.0 is the easiest solution

rennokki commented 2 years ago

@vesper8 I think that having Pusher 6.x+ and passing a client instance when creating the Pusher\Pusher instance is much better than extending the entire class :)

    'options' => [
        // ...
    ],
    'client_options' => [
        'verify' =>true, // to disable TLS checks
    ],
namespace App;

use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
use Illuminate\Broadcasting\BroadcastManager as BaseBroadcastManager;
use Psr\Log\LoggerInterface;
use Pusher\Pusher;

class TlsSupportingBroadcastManager extends BaseBroadcastManager
{
    protected function createPusherDriver(array $config)
    {
        $pusher = new Pusher(
            $config['key'], $config['secret'],
            $config['app_id'], $config['options'] ?? [],
            new \GuzzleHttp\Client($config['client_options']) ?? []
        );

        if ($config['log'] ?? false) {
            $pusher->setLogger($this->app->make(LoggerInterface::class));
        }

        return new PusherBroadcaster($pusher);
    }
}
namespace App\Providers;

use App\TlsSupportingBroadcastManager;

class BroadcastingServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(BroadcastManager::class, function ($app) {
            return new TlsSupportingBroadcastManager($app);
        });
    }
}
ckr0n commented 2 years ago

I have the same problem. i make the like @rennokki suggest but it doesnt work for me. When i start th websockets serve i see the connections to chanel. But when i try to send event from dashboard it throws an Error sending event. exception: "GuzzleHttp\\Exception\\RequestException" file: "/var/www/ckr0n/data/www/test.compit.tech/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php" line: 211 message: "cURL error 60: SSL certificate problem: unable to get local issuer certificate

bootstrap.js

broadcasting.php

thegr8awais commented 2 years ago

Any update guys?

ckr0n commented 2 years ago

In my case i had to downgrade Pusher to v5.0.3 and it work for me.

yourjhay commented 2 years ago

Experiencing this also on Ubuntu 20.4 when using Laravel 8 Brodcasting currently using certificate from GlobalSign RSA OV SSL CA 2018

anditsung commented 2 years ago

@vesper8 I think that having Pusher 6.x+ and passing a client instance when creating the Pusher\Pusher instance is much better than extending the entire class :)

  • Add this to broadcasting:
    'options' => [
        // ...
    ],
    'client_options' => [
        'verify' =>true, // to disable TLS checks
    ],
  • Extend the Illuminate\Broadcasting\BroadcastManager to create Pusher with client options:
namespace App;

use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
use Illuminate\Broadcasting\BroadcastManager as BaseBroadcastManager;
use Psr\Log\LoggerInterface;
use Pusher\Pusher;

class TlsSupportingBroadcastManager extends BaseBroadcastManager
{
    protected function createPusherDriver(array $config)
    {
        $pusher = new Pusher(
            $config['key'], $config['secret'],
            $config['app_id'], $config['options'] ?? [],
            new \GuzzleHttp\Client($config['client_options']) ?? []
        );

        if ($config['log'] ?? false) {
            $pusher->setLogger($this->app->make(LoggerInterface::class));
        }

        return new PusherBroadcaster($pusher);
    }
}
  • Re-instantiate the BroadcastManager at runtime:
namespace App\Providers;

use App\TlsSupportingBroadcastManager;

class BroadcastingServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(BroadcastManager::class, function ($app) {
            return new TlsSupportingBroadcastManager($app);
        });
    }
}

this fix only available for laravel v9

LingaTigeen commented 2 years ago

I had the same issue. I downloaded the https://curl.se/ca/cacert.pem as per https://curl.se/docs/caextract.html and added to my php.ini

[curl] curl.cainfo = "C:\xampp\php\extras\ssl\cacert.pem"

[openssl] openssl.cafile = "C:\xampp\php\extras\ssl\cacert.pem"

No need to have the 'client_options' in broadcasting.php

bilalsheikh1 commented 2 years ago

In my case i had to downgrade Pusher to v5.0.3 and it work for me.

is it pusher-server or pusher js

vesper8 commented 2 years ago

In my case i had to downgrade Pusher to v5.0.3 and it work for me.

is it pusher-server or pusher js

The service you have to downgrade is the php dependency pusher/pusher-php-server using Composer

https://packagist.org/packages/pusher/pusher-php-server

You do not have to downgrade the client-side https://www.npmjs.com/package/pusher-js

YassineChe commented 2 years ago

Any update?

ven0ms99 commented 2 years ago

I'm wondering as well. Having to use such an old version of pusher/pusher-php-server cannot be the solution here.

anditsung commented 2 years ago

I'm wondering as well. Having to use such an old version of pusher/pusher-php-server cannot be the solution here.

either update to laravel 9 or use old version of pusher-php-server 5.0.3

ven0ms99 commented 2 years ago

I'm on Laravel 9, @anditsung. I get this error: cURL error 60: SSL certificate problem: unable to get local issuer certificate

With pusher-php-server 5.x everything works just fine.

anditsung commented 2 years ago

I'm on Laravel 9, @anditsung. I get this error: cURL error 60: SSL certificate problem: unable to get local issuer certificate

With pusher-php-server 5.x everything works just fine.

update from laravel 7 or 8?

config/broadcasting.php

'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                'host' => env('PUSHER_HOST', 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
                'port' => env('PUSHER_PORT', 443),
                'scheme' => env('PUSHER_SCHEME', 'https'),
                'encrypted' => true,
                'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
            ],
            'client_options' => [
                // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
            ],
        ],

is your config like this?

ven0ms99 commented 2 years ago

@anditsung oh, I was definitely missing something there. Updated it according to Laravel 9 and it's working now. This was before:

            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                'cluster' => env('PUSHER_APP_CLUSTER'),
                'host' => '127.0.0.1',
                'port' => 6001,
                'scheme' => 'https',
                'curl_options' => [
                    CURLOPT_SSL_VERIFYHOST => env('APP_ENV') === "local" ? 0 : 2,
                    CURLOPT_SSL_VERIFYPEER => env('APP_ENV') === "local" ? 0 : 1,
                ]
            ],
jloguercio commented 2 years ago

Ok, after hours of testing I have been able to solve this problem and the only viable way I have found is to downgrade the version of pusher server to 4.1.

Im using :

So, im downgrade pusher server using:

composer require pusher/pusher-php-server "^4.1"

my broadcasting.php :

'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                'cluster' => env('PUSHER_APP_CLUSTER'),
                'scheme' => env('PUSHER_APP_SCHEME'),
                'host' => '127.0.0.1',
                'port' => 6001,
                'curl_options' => [
                    CURLOPT_SSL_VERIFYHOST => 0,
                    CURLOPT_SSL_VERIFYPEER => 0,
                ]
            ],
        ],

My websockets.php :

    'ssl' => [
        /*
         * Path to local certificate file on filesystem. It must be a PEM encoded file which
         * contains your certificate and private key. It can optionally contain the
         * certificate chain of issuers. The private key also may be contained
         * in a separate file specified by local_pk.
         */
        'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),

        /*
         * Path to local private key file on filesystem in case of separate files for
         * certificate (local_cert) and private key.
         */
        'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),

        /*
         * Passphrase for your local_cert file.
         */
        'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),

        /*
         * Verifying SSL Peer’s Certificate.
         */
        'verify_peer' => env('LARAVEL_WEBSOCKETS_VERIFY_PEER', false),

        /*
         * Allow Self Signed Certificates.
         */
        'allow_self_signed' => env('LARAVEL_WEBSOCKETS_ALLOW_SELF_SIGNED', false),
    ],

Im using LARAVEL_WEBSOCKETS_SSL_LOCAL_PK and LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT in .env file to point my server certs in my production server.

my app.js :

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    wsHost: process.env.MIX_SHORT_URL,
    forceTLS: false,
    wsPort: 6001,
    wssPort: 6001,
    encrypted: true,
    disableStats: true,
    enabledTransports: ['ws', 'wss']
});

This configuration works fine in both environments : local computer without ssl (http) and production server with ssl cert (https)

hope this helps

rizkhal commented 1 year ago

i use "pusher/pusher-php-server": "^7.0" and i disable verify TLS via client_options, not from curl_options

'client_options' => [
    'verify' => false, // to disable TLS checks
],

refer from this comment

bci24 commented 1 year ago

I am using laravel 9 with laravel-websockets 1.13.1 and pusher/pusher-php-server 7.2.1 and a self signed ssl for localhost

I have set this in broadcasting.php

'client_options' => [
    'verify' => false, // to disable TLS checks
],

and the error is gone

cURL error 60: SSL certificate problem: seflt signed certificate ....

but the it does not work ... the listener is not triggered.

I want to work in dev with self signed sert. (https://localhost)

Any ideas?

rizkhal commented 1 year ago

@bci24 u must upload ur certificae to ur browser, chek it on SETTING -> SSL and upload it

bci24 commented 1 year ago

@rizkhal the certificate was already imported ... anyway the problem is the event is not triggered. I have tested also without secure connection (http) and the same thing happens.

The working project was using laravel-echo-server with socket.io and now I have migrated to laravel-websockets

In the app.js I have this:

import Echo from 'laravel-echo'
window.Pusher = require('pusher-js')

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    wsHost: process.env.MIX_PUSHER_HOST,
    wsPort: process.env.MIX_PUSHER_PORT,
    wssPort: process.env.MIX_PUSHER_PORT,
    encrypted: true,
    disableStats: true,
    forceTLS: true,
    enabledTransports: ['ws', 'wss'],
})

And in the component that is is listening the event (and is not triggered)

onMounted(() => {
    window.Echo.channel('visitors').listen('.VisitorEvent',(data) => {
        console.log(data) // it is not executed !!!
    })
}) 

In the images attached you can see that the connection is made, is connected to the channel "visitors"

1

2

rizkhal commented 1 year ago

@bci24 how about with namespace?

onMounted(() => {
    window.Echo.channel('visitors').listen('.App\\Events\\VisitorEvent',(data) => {
        console.log(data) // it is not executed !!!
    })
}) 
bci24 commented 1 year ago

@rizkhal tested and the same. The problem seems to be on the laravel-websockets side.

I have tested with the same config with ssl using the npm server soketi and it works. The events are triggered. When using the laravel-websockets it doesn't work.

Now the laravel-websockets is installed on a fresh laravel 9 ... to be used as a stand alone server - multi tenant.

I have also integrated with the main project for testing and the same thing ... it connects to the socket but the events are not triggered....

bci24 commented 1 year ago

@rizkhal I know this issue is not relevant to my problem.... sorry for spam...

I wanted to tell that now is working. The are 2 solutions:

1) downgrade the pusher-php-server to 7.0.2 2) use the latest pusher-php-server 7.2.1 and update the TriggerEventController manually https://github.com/beyondcode/laravel-websockets/pull/1046/commits/fe78daf914aa5a60d47402b2d0b6390e83c9102a

rebeb74 commented 1 year ago

I had this issue too and I found this solution using SSL certificates:

Configuration: "beyondcode/laravel-websockets": "^1.13", "laravel/framework": "^9.19", "pusher/pusher-php-server": "^7.0"

broadcasting.php

'connections' => [
    'pusher' => [
        'driver' => 'pusher',
        'key' => env('PUSHER_APP_KEY'),
        'secret' => env('PUSHER_APP_SECRET'),
        'app_id' => env('PUSHER_APP_ID'),
        'options' => [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            'useTLS' => true,
            'encrypted' => true,
            'host' => env('PUSHER_HOST'),
            'port' => env('LARAVEL_WEBSOCKETS_PORT'),
            'scheme' => 'https',
        ],
        'client_options' => [
            'verify' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT'),
        ],
    ],

    ...

],

websockets.php

'ssl' => [
    'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),
    'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),
    'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
    'verify_peer' => false,
    'allow_self_signed' => true,
]

The curl 'client_options' worked without any change on other files.

endrik-exe commented 1 year ago

Hi All, I have simpler solution to this.

Yes it turns out that latest version of pusher has no 'client_options' options and also 'curl_options' So i dig to the source code, and found that no options is passed to the Guzzle Client.

But they allow us to pass custom guzzle client when creating Pusher, so here is the shortest and simplest solution.

  1. In your AppServiceProvider

    public function boot(BroadcastManager $broadcastManager): void
    {
    //Create custom pusher, because they don't allow us to modify Guzzle client via config broadcasting.php, make sure you set pusher-custom in .env
    $broadcastManager->extend('pusher-custom', function (Application $app, array $config) {
        $client = new \GuzzleHttp\Client(['verify' => false]);
    
        $options = [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            'encrypted' => true,
            'host' => '127.0.0.1',
            'port' => env('PUSHER_PORT', 6005),
            'useTLS' => env('PUSHER_SCHEME') == 'https',
            'scheme' => env('PUSHER_SCHEME', 'http'),
        ];
    
        $pusher = new Pusher(
            env('PUSHER_APP_KEY'),
            env('PUSHER_APP_SECRET'),
            env('PUSHER_APP_ID'),
            $options,
            $client //set custom guzzle client
        );
    
        return new PusherBroadcaster($pusher);
    });
    
    Schema::defaultStringLength(191);
    }
  2. Add pusher-custom in broadcasting.php

    'connections' => [
        'pusher-custom' => [
            'driver' => 'pusher-custom'
        ],
        'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
  3. then change broadcast driver to pusher-custom in .env BROADCAST_DRIVER=pusher-custom

Thank me later

Waseem-Alhabash commented 1 year ago

Hi All, I have simpler solution to this.

Yes it turns out that latest version of pusher has no 'client_options' options and also 'curl_options' So i dig to the source code, and found that no options is passed to the Guzzle Client.

But they allow us to pass custom guzzle client when creating Pusher, so here is the shortest and simplest solution.

  1. In your AppServiceProvider
public function boot(BroadcastManager $broadcastManager): void
{
    //Create custom pusher, because they don't allow us to modify Guzzle client via config broadcasting.php, make sure you set pusher-custom in .env
    $broadcastManager->extend('pusher-custom', function (Application $app, array $config) {
        $client = new \GuzzleHttp\Client(['verify' => false]);

        $options = [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            'encrypted' => true,
            'host' => '127.0.0.1',
            'port' => env('PUSHER_PORT', 6005),
            'useTLS' => env('PUSHER_SCHEME') == 'https',
            'scheme' => env('PUSHER_SCHEME', 'http'),
        ];

        $pusher = new Pusher(
            env('PUSHER_APP_KEY'),
            env('PUSHER_APP_SECRET'),
            env('PUSHER_APP_ID'),
            $options,
            $client //set custom guzzle client
        );

        return new PusherBroadcaster($pusher);
    });

    Schema::defaultStringLength(191);
}
  1. Add pusher-custom in broadcasting.php
'connections' => [
        'pusher-custom' => [
            'driver' => 'pusher-custom'
        ],
        'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
  1. then change broadcast driver to pusher-custom in .env BROADCAST_DRIVER=pusher-custom

Thank me later

Works for me on Laravel 10

a-di-ez commented 1 year ago

Hi All, I have simpler solution to this.

Yes it turns out that latest version of pusher has no 'client_options' options and also 'curl_options' So i dig to the source code, and found that no options is passed to the Guzzle Client.

But they allow us to pass custom guzzle client when creating Pusher, so here is the shortest and simplest solution.

  1. In your AppServiceProvider
public function boot(BroadcastManager $broadcastManager): void
{
    //Create custom pusher, because they don't allow us to modify Guzzle client via config broadcasting.php, make sure you set pusher-custom in .env
    $broadcastManager->extend('pusher-custom', function (Application $app, array $config) {
        $client = new \GuzzleHttp\Client(['verify' => false]);

        $options = [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            'encrypted' => true,
            'host' => '127.0.0.1',
            'port' => env('PUSHER_PORT', 6005),
            'useTLS' => env('PUSHER_SCHEME') == 'https',
            'scheme' => env('PUSHER_SCHEME', 'http'),
        ];

        $pusher = new Pusher(
            env('PUSHER_APP_KEY'),
            env('PUSHER_APP_SECRET'),
            env('PUSHER_APP_ID'),
            $options,
            $client //set custom guzzle client
        );

        return new PusherBroadcaster($pusher);
    });

    Schema::defaultStringLength(191);
}
  1. Add pusher-custom in broadcasting.php
'connections' => [
        'pusher-custom' => [
            'driver' => 'pusher-custom'
        ],
        'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
  1. then change broadcast driver to pusher-custom in .env BROADCAST_DRIVER=pusher-custom

Thank me later

More correct version


    public function boot(): void
    {
        app(BroadcastManager::class)->extend('pusher-custom', function () {
            $pusher = new Pusher(
                config('broadcasting.connections.pusher.key'),
                config('broadcasting.connections.pusher.secret'),
                config('broadcasting.connections.pusher.app_id'),
                config('broadcasting.connections.pusher.options'),
                new \GuzzleHttp\Client(['verify' => false]),
            );

            return new PusherBroadcaster($pusher);
        });
    }
michalevk commented 11 months ago

Cześć wszystkim, mam prostsze rozwiązanie tego problemu. Tak, okazuje się, że najnowsza wersja pushera nie ma opcji „client_options”, a także „curl_options”. Przeszukałem więc kod źródłowy i odkryłem, że do klienta Guzzle nie są przekazywane żadne opcje. Ale pozwalają nam przekazać niestandardowego klienta żarcia podczas tworzenia Pushera, więc oto najkrótsze i najprostsze rozwiązanie.

  1. W swoim AppServiceProvider
public function boot(BroadcastManager $broadcastManager): void
{
    //Create custom pusher, because they don't allow us to modify Guzzle client via config broadcasting.php, make sure you set pusher-custom in .env
    $broadcastManager->extend('pusher-custom', function (Application $app, array $config) {
        $client = new \GuzzleHttp\Client(['verify' => false]);

        $options = [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            'encrypted' => true,
            'host' => '127.0.0.1',
            'port' => env('PUSHER_PORT', 6005),
            'useTLS' => env('PUSHER_SCHEME') == 'https',
            'scheme' => env('PUSHER_SCHEME', 'http'),
        ];

        $pusher = new Pusher(
            env('PUSHER_APP_KEY'),
            env('PUSHER_APP_SECRET'),
            env('PUSHER_APP_ID'),
            $options,
            $client //set custom guzzle client
        );

        return new PusherBroadcaster($pusher);
    });

    Schema::defaultStringLength(191);
}
  1. Dodaj pusher-custom w nadawania.php
'connections' => [
        'pusher-custom' => [
            'driver' => 'pusher-custom'
        ],
        'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
  1. następnie zmień sterownik rozgłoszeniowy na pusher-custom w .env BROADCAST_DRIVER=pusher-custom

Podziękujesz mi później

Bardziej poprawna wersja

    public function boot(): void
    {
        app(BroadcastManager::class)->extend('pusher-custom', function () {
            $pusher = new Pusher(
                config('broadcasting.connections.pusher.key'),
                config('broadcasting.connections.pusher.secret'),
                config('broadcasting.connections.pusher.app_id'),
                config('broadcasting.connections.pusher.options'),
                new \GuzzleHttp\Client(['verify' => false]),
            );

            return new PusherBroadcaster($pusher);
        });
    }

InvalidArgumentException

Driver [pusher-custom] is not supported.

at vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastManager.php:259 255▕ 256▕ $driverMethod = 'create'.ucfirst($config['driver']).'Driver'; 257▕ 258▕ if (! method_exists($this, $driverMethod)) { ➜ 259▕ throw new InvalidArgumentException("Driver [{$config['driver']}] is not supported."); 260▕ } 261▕ 262▕ return $this->{$driverMethod}($config); 263▕ }

  +18 vendor frames

19 [internal]:0 Illuminate\Foundation\Application::Illuminate\Foundation{closure}(Object(RTippin\Messenger\MessengerServiceProvider)) +5 vendor frames

25 artisan:37 Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))