pusher / pusher-websocket-react-native

React Native official Pusher SDK
MIT License
62 stars 55 forks source link

403 Forbidden #24

Closed nattive closed 1 year ago

nattive commented 2 years ago

ISSUE

/broadcasting/auth        403 Forbidden   

I am using laravel as the backend for this package, i cant seem to find a way to set the bearer token at the header in other to subscribe to to a private channel.

Snippet

const connect = async () => {
            try {
                await pusher.init({
                    apiKey: "****",
                    authEndpoint: 'https://....ngrok.io/broadcasting/auth',
                    cluster: "mt1",
                    onEvent: (event) => {
                        console.log(event);
                    }, 
                    onSubscriptionSucceeded,
                    onDecryptionFailure: (event) => {
                        console.log('onDecryptionFailure', event);
                    }
                });
                await pusher.connect();

                let myChannel = await pusher.subscribe({
                    channelName: "my-channel", onEvent: (event) => {
                        console.log(`onEvent: ${event}`);
                    }
                });

                let privateChannel = await pusher.subscribe({
                    channelName: `private-User.${user?.id}`, onEvent: (event) => {
                        console.log(`onEvent: ${event}`);
                    }
                });
                console.log(privateChannel);

            } catch (e) {
                console.log('ERROR: ' + e);
            }
        };
benw-pusher commented 2 years ago

In order to set your own headers you would need to use the onAuthorizer callback to provide your own way of calling your auth endpoint, including setting any available headers.

errorstudent commented 2 years ago

I got the same issue because to access the authEndpoint need an Authorization header. It would be very helpful if someone could point out the solution or example, thanks.

alexscarlett commented 2 years ago

@benw-pusher (or any pusher devs) — is there an example you could give here or elaborate on exactly how to do this?

The new documentation seems to lack an explanation of how to achieve this with this new RN lib (or if it is deep in there somewhere I'm sure I'm not the only one who'd love a nudge in the right direction 🙂).

All I've been able to find in the new docs is the onAuthorizer section in the README and generating authorization strings for what seems like the default Pusher auth endpoint...but nothing on how to provide the correct params for a custom authEndpoint if it is provided.

TDLR...this config obj is how we got the pusher-js lib to allow us to subscribe to private user channels previously, but there doesn't seem a trivial way to do this in the new lib.

const pusherConfig = {
  ...otherConfigStuff,
  authEndpoint: <custom-endpoint>,
  auth: {
    headers: { Authorization: `Bearer ${apiUserToken}` },
  }
}

Is there a way to achieve this or will we have to wait for some further development?

Also, a quick side note...once you land in the official pusher docs, it seems to only explain the pusher-js way of doing things which is a bit confusing since some links in this repo point you there.

alexsymbol commented 2 years ago

Works for me, call your endpoint with channelName and socketId parameters, backend return { auth, channel_data } information

init auth
alexscarlett commented 2 years ago

@alexsymbol ty for the code snippets!

are you able to subscribe to private channels after doing the above? I see the onAuthorizer call with the correct data being passed through, but no luck getting private events to show.

alexsymbol commented 2 years ago

yes I can, check the onSubscriptionError methods to find out what the problem is

Screenshot at Sep 28 18-10-07
sin2 commented 2 years ago

I am connecting the same way as commented above. However on iOS I am also not able to subscribe. Also, none of the error callbacks are being fired. Android works as intented.

pusher
  .init({
    apiKey: Config.PUSHSER_KEY,
    cluster: Config.PUSHSER_CLUSTER,
    async onAuthorizer(channelName, socketId) {
      const token = await auth().currentUser?.getIdToken();
      try {
        const res = await fetch(Config.PUSHER_AUTH_ENDPOINT, {
          method: "POST",
          headers: new Headers({
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`,
          }),
          body: JSON.stringify({
            socket_id: socketId,
            channel_name: channelName,
          }),
        });

        if (!res.ok) {
          throw new Error(`Pusher: Received ${res.status} from ${res.url}`);
        }

        const data = await res.json();
        return data;
      } catch (error) {
        console.error("Failed to authenticate");
      }
    },
    onConnectionStateChange: (state) => {
      console.info("Pusher:", state);
    },
    onSubscriptionSucceeded(channelName, data) {
      console.info("Pusher: Subscribed to ", channelName, data);
    },
    onSubscriptionError(channelName, message, e) {
      console.error("Pusher: Failed to subscribe to ", channelName, message, e);
    },
    onDecryptionFailure(eventName, reason) {
      console.error("Pusher: Decryption failure", eventName, reason);
    },
    onError(message, code, e) {
      console.error("Pusher: Error", message, code, e);
    },
  })
  .then(() => {
    pusher.connect();
  })
  .catch(console.error);
alexsymbol commented 2 years ago

@sin2 your backend also expects fields _socketid and _channelname ?

sin2 commented 2 years ago

Yes, and returns an object with an auth field. ie. { "auth" : "..." }

alexsymbol commented 2 years ago

I think the problem with this line const data = await res.json(); Try to use destructuring without line above const { data } = await fetch(Config.PUSHER_AUTH_ENDPOINT, {,

Also try to remove this line if (!res.ok) { throw new Error(Pusher: Received ${res.status} from ${res.url}); }

P.S. you don't need to use try/catch, for catch an error you have onSubscriptionError method

sin2 commented 2 years ago

Property 'data' does not exist on type 'Response'.ts Fetch doesn't return a data property.

After removing the try/catch there is still no error being fired. Also, this is working for android devices.

alexscarlett commented 2 years ago

@alexsymbol FWIW I am also seeing the same behavior as @sin2 on iOS...

alexsymbol commented 2 years ago

Property 'data' does not exist on type 'Response'.ts Fetch doesn't return a data property.

After removing the try/catch there is still no error being fired. Also, this is working for android devices.

I use axios library for request

alexsymbol commented 2 years ago

@sin2 @alexscarlett Try to use this syntax for channelName

const channelName = `presence-post-${adminId}-channel-${channel}`;

      await pusher.subscribe({
        channelName,
        onSubscriptionSucceeded: data => {
          console.log('data', data);
        },
        onSubscriptionError,
        onEvent: async (event: PusherEvent) => {
          console.log('event: ', event);
        },
      });
sin2 commented 2 years ago

What would adminId and channel be in with this syntax?

alexsymbol commented 2 years ago

this question already belongs to another topic, you can post your sample code in the topic with the ability to subscribe to the channel itself because the original question was about authorization problems

sin2 commented 2 years ago

I think this is still an authorization problem. I know subscription works correctly given that it works on Android. Unless there is a difference I am not understanding between implementations on both platforms. At the very least, onAuthorizer should be better documented.

For now, I unfortunately have switched back to using the pusher-js library.

I should also add, that I am able to successfully subscribe to public channels.

edit: I suspect my issue is related to https://github.com/pusher/pusher-websocket-react-native/issues/34. After trying https://github.com/pusher/pusher-websocket-react-native/pull/36 I was able to successfully subscribe.

fbenevides commented 1 year ago

@sin2 We've just released 1.2.0 which solves this issue on iOS. We'll be working on fixing this issue on Android for the next releases.