pusher / pusher-channels-flutter

Pusher Channels client library for Flutter targeting IOS, Android, and WEB
MIT License
72 stars 107 forks source link

Can't Subscribe to Private Channel #34

Open JordanDalton opened 2 years ago

JordanDalton commented 2 years ago

I am attempting to subscribe to a private channel. The following is the instantiation of Pusher:

PusherChannelsFlutter pusher = PusherChannelsFlutter.getInstance();
var myChannelName = 'private-MyChannel';

try {

      await pusher.init(
        apiKey: '85fa4e3311f746a5ce25',
        cluster: 'us2',
        //authEndpoint: "https://9d1afc49846e.ngrok.io/mapi/auth",
        onConnectionStateChange: onConnectionStateChange,
        onError: onError,
        onSubscriptionSucceeded: onSubscriptionSucceeded,
        onEvent: onEvent,
        onSubscriptionError: onSubscriptionError,
        onDecryptionFailure: onDecryptionFailure,
        onMemberAdded: onMemberAdded,
        onMemberRemoved: onMemberRemoved,
        onAuthorizer: onAuthorizer
      );
      await pusher.subscribe(channelName: myChannelName);
      await pusher.connect();
    } catch (e) {
      print("ERROR: $e");
    }

Given it's a private channel onAuthorizer get's called:

dynamic onAuthorizer(String channelName, String socketId, dynamic options) {

    print('////onAuthorizer');

    var response = Api().post('auth', {
      "socket_id": socketId,
      "channel_name": channelName,
    });

    var data = null;

    response.then((response){
      data = response.data;

      return jsonDecode(data); // {"auth":"<redacted>:<redacted>"}
    });
  }

On Pusher's debug console the Subscribed event never gets triggered.

benw-pusher commented 2 years ago

Do you receive any error messages when the subscription is attempted? You should see these in the client, or alternatively some error messages will be present in the Pusher Dashboard under the Error Log section?

It looks like your onAuthorizer code is making a request to an endpoint, can you share the code that returns the auth token from that endpoint?

JordanDalton commented 2 years ago

I received no success nor error message on the subscription. These are the callbacks I have defined:

  void onSubscriptionSucceeded(String channelName, dynamic data) {
    print("onSubscriptionSucceeded: $channelName data: $data");
  }

   void onSubscriptionError(String message, dynamic e) {
    print("onSubscriptionError: $message Exception: $e");
  }

Here's my controller from my Laravel app:

<?php

namespace App\Http\Controllers\MobileApi;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Pusher\Pusher;

class PusherAuthController extends Controller
{
    public function __invoke(Request $request)
    {
        \Log::info('PusherAuthController', $request->toArray());

        $pusher = new Pusher(
            env('PUSHER_MOBILE_APP_KEY'),
            env('PUSHER_MOBILE_APP_SECRET'),
            env('PUSHER_MOBILE_APP_ID')
        );

        $channel     = request('channel_name');
        $socket_id   = request('socket_id');

        return $pusher->socket_auth($channel, $socket_id);
    }
}

This produces a response in the following format:

{"auth":"<redacted>:<redacted>"}

benw-pusher commented 2 years ago

I would expect that, if this authController is returning the auth token in the correct format (which it appears to be) then there should be an error emitted at the client. This error would likely be to indicate that the token returned is incorrect in some way. Are you able to open a support ticket so we can look up your app details and you can share the generated token and investigate? You can do so at support.pusher.com.

JordanDalton commented 2 years ago

I'll put in a ticket. My theory is that with onAuthorizer there's an async request to call my endpoint. Technically that method would return null before the API request completed.

JordanDalton commented 2 years ago

If authParams can offer support for Android and iOS this would resolve my issue.

proggen-com commented 2 years ago

Can you try something like:

dynamic onAuthorizer(String channelName, String socketId, dynamic options) async {
    print('////onAuthorizer');
    var response = await Api().post('auth', {
      "socket_id": socketId,
      "channel_name": channelName,
    });
    return jsonDecode(response.data);
}
JordanDalton commented 2 years ago

I tried that but found that it only worked with public channels.

solpreneur commented 2 years ago

This worked for me.

When using the onAuthorizer method, don't set the authEndpoint option when initializing pusher.

Future<void> _initializePusher() async {

    //singleton pusher instance
    var pusher= PusherChannelsFlutter.getInstance();

    await pusher.init(
        apiKey: pusherData.apiKey,
        cluster: pusherData.cluster,
        onError: onError,
        onEvent: onEvent,
        onSubscriptionError: onSubscriptionError,
        onAuthorizer: onAuthorizer);

    channel = (await pusher.subscribe(channelName: channelName));
    await pusher.connect();
  }
dynamic onAuthorizer(
      String channelName, String socketId, dynamic options) async {
    var authUrl = baseUrl + '/broadcasting/auth';
    var result = await post(
      Uri.parse(authUrl),
      headers: {
         'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Bearer ${token}',
      },
      body: 'socket_id=' + socketId + '&channel_name=' + channelName,
    );
    return jsonDecode(result.body);
  }
yacinegithub commented 2 years ago

This worked for me.

When using the onAuthorizer method, don't set the authEndpoint option when initializing pusher.

Future<void> _initializePusher() async {

    //singleton pusher instance
    var pusher= PusherChannelsFlutter.getInstance();

    await pusher.init(
        apiKey: pusherData.apiKey,
        cluster: pusherData.cluster,
        onError: onError,
        onEvent: onEvent,
        onSubscriptionError: onSubscriptionError,
        onAuthorizer: onAuthorizer);

    channel = (await pusher.subscribe(channelName: channelName));
    await pusher.connect();
  }
dynamic onAuthorizer(
      String channelName, String socketId, dynamic options) async {
    var authUrl = baseUrl + '/broadcasting/auth';
    var result = await post(
      Uri.parse(authUrl),
      headers: {
         'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Bearer ${token}',
      },
      body: 'socket_id=' + socketId + '&channel_name=' + channelName,
    );
    return jsonDecode(result.body);
  }

Hi, do you use laravel websockets pusher replacement method, if so where i have to set the Host name/address when initiate Pusher?

gtu-myowin commented 2 years ago

@yacinegithub this https://github.com/pusher/pusher-channels-flutter/issues/41#issuecomment-1101549333 could help you

lailai0715 commented 2 years ago

This worked for me. When using the onAuthorizer method, don't set the authEndpoint option when initializing pusher.

Future<void> _initializePusher() async {

    //singleton pusher instance
    var pusher= PusherChannelsFlutter.getInstance();

    await pusher.init(
        apiKey: pusherData.apiKey,
        cluster: pusherData.cluster,
        onError: onError,
        onEvent: onEvent,
        onSubscriptionError: onSubscriptionError,
        onAuthorizer: onAuthorizer);

    channel = (await pusher.subscribe(channelName: channelName));
    await pusher.connect();
  }
dynamic onAuthorizer(
      String channelName, String socketId, dynamic options) async {
    var authUrl = baseUrl + '/broadcasting/auth';
    var result = await post(
      Uri.parse(authUrl),
      headers: {
         'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Bearer ${token}',
      },
      body: 'socket_id=' + socketId + '&channel_name=' + channelName,
    );
    return jsonDecode(result.body);
  }

Hi, do you use laravel websockets pusher replacement method, if so where i have to set the Host name/address when initiate Pusher?

Same issue here, how can I insert custom port and host?

gtu-myowin commented 2 years ago

@lailai0715 You don't need those information. See the initialization here or my comment https://github.com/pusher/pusher-channels-flutter/issues/41#issuecomment-1101549333

kwul0208 commented 2 years ago

how to get socketId()?

ziagit commented 1 year ago

Dear @solpreneur I get null from broadcusting/auth this is init

try {
      await pusher.init(
        apiKey: _apiKey.text,
        cluster: _cluster.text,
        onConnectionStateChange: onConnectionStateChange,
        onError: onError,
        onSubscriptionSucceeded: onSubscriptionSucceeded,
        onEvent: onEvent,
        onSubscriptionError: onSubscriptionError,
        onDecryptionFailure: onDecryptionFailure,
        onMemberAdded: onMemberAdded,
        onMemberRemoved: onMemberRemoved,
        //authEndpoint: "https://my-website.com/broadcasting/auth",
        onAuthorizer: onAuthorizer,
      );
      await pusher.subscribe(channelName: _channelName.text);
      await pusher.connect();
    } catch (e) {
      print("$e");
      log("ERROR: $e");
    }

and this is the onAuthorizer function

 dynamic onAuthorizer(
      String channelName, String socketId, dynamic options) async {
    var authUrl = "https://my-website.com/broadcasting/auth";
    var result = await http.post(
      Uri.parse(authUrl),
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Bearer ${token}',
      },
      body: 'socket_id=' + socketId + '&channel_name=' + channelName,
    );
    return jsonDecode(result.body);
  }

I tried content-type as json too but same result

      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ${token}',
      }

this is the error I get

[  +65 ms] I/PusherChannelsFlutter(20214): Start com.pusher.client.Pusher@4083fc0
[ +102 ms] I/flutter (20214): LOG: Connection: CONNECTING
[+1566 ms] I/flutter (20214): LOG: Connection: CONNECTED
[+1566 ms] I/flutter (20214): LOG: onSubscriptionError: Unable to parse response from Authorizer: null Exception: com.pusher.client.AuthorizationFailureException: Unable to parse
response from Authorizer: null

the backend is Laravel the route broadcasting/auth is bydefault created

benw-pusher commented 1 year ago

@ziagit An empty response from broadcast/auth could indicate an error when generating the necessary token - for example the broadcast driver not being set correctly to the app credentials in the .env file being missing/invalid.

benw-pusher commented 1 year ago

@kwul0208 you can get the socket ID using the method described at https://github.com/pusher/pusher-channels-flutter#socket-information

mahmoudmaray2000 commented 1 year ago

@benw-pusher can you provide a method to send AuthOptions with pusher.init i think it will solve the problem

ziagit commented 1 year ago

I solved this problem, if anyone else has such a problem look here