Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.3] Pusher authentication across domains #15746

Closed
jedjones-uk opened this issue Oct 4, 2016 · 5 comments
Closed

[5.3] Pusher authentication across domains #15746

jedjones-uk opened this issue Oct 4, 2016 · 5 comments

Comments

@jedjones-uk
Copy link

  • Laravel Version: 5.3.15
  • PHP Version: PHP 7.0.8-2+deb.sury.org~xenial+1 (cli) ( NTS )

I currently use Laravel as an API and have an AngularJS client side running on a separate domain, authentication is handled with cookies, and not auth tokens.

When using pusher across domains on private channels it does not attach the credentials to the request, the only way I found to do it is by setting authTransport: 'jsonp' in the Echo options, but when you do this the authentication request made by pusher is a GET request and pusher expects a callback as the response. With the small changes below, it will allow the pusher broadcaster to be used when the auth domain is different from the requesting domain.

I have modified PusherBroadcaster.php as follows to make it work:

public function validAuthenticationResponse($request, $result) {
   $callback = $request->has('callback') ? $request->get('callback') : null;

    if (Str::startsWith($request->channel_name, 'private')) {
        return $this->decodePusherResponse(
                        $this->pusher->socket_auth($request->channel_name, $request->socket_id), $callback
        );
    } else {
        return $this->decodePusherResponse(
                        $this->pusher->presence_auth(
                                $request->channel_name, $request->socket_id, $request->user()->id, $result), $callback
        );
    }
}

protected function decodePusherResponse($response, $callback = null) {
    if ($callback !== null) {
        return $callback . '(' . $response . ');';
    } else {
        return json_decode($response, true);
    }
}

I also had to change Illuminate\Broadcasting\BroadcastManager@routes to include a GET endpoint like so:

 $this->app['router']->group($attributes, function ($router) {
        $router->post('/broadcasting/auth', BroadcastController::class.'@authenticate');
        $router->get('/broadcasting/auth', BroadcastController::class.'@authenticate');
    });

Is there a better way to handle what I am doing?

@themsaid
Copy link
Member

themsaid commented Oct 4, 2016

Can you please explain your changes? I don't seem to follow, why do you think these changes solve your problem?

@jedjones-uk
Copy link
Author

Sure, I have 3 parts to my application:
api.laravel.dev - A Laravel 5.3 based API using Sentinal with cookies for Authentication
app.laravel.dev - An AngularJS user interface
and pusher in between

I was going through the process of setting up broadcasts to send notifications to my UI and found that when Laravel Echo makes the authentication request to my API for private channels, it did not attach any credentials to the request, and they would fail (403). This is because my API is on a different domain to the Echo Javascript.

After reading through pusher docs (https://pusher.com/docs/authenticating_users) I found that the only way to do the cross domain authentication is with JSONp, this can be set in Laravel Echo with authTransport: 'jsonp'. The problem is the request that pusher makes to the authEndpoint when using JSONp is a GET request, not a POST request as normal. This is why I had to modify Illuminate\Broadcasting\BroadcastManager@routes to also accept a GET request on the route.

The other difference is pusher expects the authentication signature to be returned in a callback when using JSONp, not just the standard JSON format. I have modified Illuminate\Broadcasting\Broadcasters\PusherBroadcaster@validAuthenticationResponse to look for a callback parameter that the pusher-js attaches to its request, and if it finds it to pass it on to the decodePusherResponse function in the same class. If a callback parameter was attached to the request, then we can assume pusher made a JSONp request, and return the correctly formatted response.

These changes have fixed my problem entirely and now the broadcasting works, I am not sure if there is a better place to achieve the same results, or a better place to modify the broadcast package, but I figured once the problem and solution were detailed, the Laravel team would be able to make that decision.

@morloderex
Copy link
Contributor

ping @themsaid.
His expianation is acutally pretty solid but not sure i like his impimentation tho.

@jedjones-uk No offense, but this doesn't seem so clean to me.

@jedjones-uk
Copy link
Author

@morloderex None taken, I wanted to raise the issue and at least provide a solution with the problem, but I knew it was quite likely there would be a better/cleaner/more Laravel way of handling it.

@acidjazz
Copy link
Contributor

It's hard to believe years later I'm trying to authenticate with pusher cross-domain and all I can find is this unresolved issue, is there no fix/workaround in 5.6 now @jedjones-uk @morloderex @themsaid ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants