Search code examples
pythondjangopusherpusher-js

Pusher - autenticated users not receiving events from private channels


Let's say I have a vue client trying to receive an event from a private channel using pusher services.

This client autenticates using pusher auth secuence: enter image description here

Here are the docs: https://pusher.com/docs/channels/server_api/authenticating-users/

Seems I need to provide an endpoint on my server in order to autenticate the user.

So, as the docs says, since my server is in a different domain to the front-end app, I need to use CORS or JSONP, I choose JSONP.

My server (backend) is made in Django using django-rest-framework and it provides an endpoint that is responsible to process the socket_id, the channel_name and the callback that the pusher-js (which is a pusher frontend library) generates.

Something alike to a javascript code is sent to the frontend, so the response needs to be content-type:application/javascript.

In order to test the event, I made a simple python script which I will later integrate to my bussiness logic. This script is the responsible to trigger the event.

The problem: The main problem is the event never arrives. I looked up into the web-console (frontend) to check the correct function of the requests. The ws protocol requests responds with status 101 and the endpoint /auth/pusher with status 200. So they seem to work correctly.

  • Here is my Django /auth/pusher endpoint:
def get(self, request):
  pusher_client = pusher.Pusher(
      app_id = settings.P_APP_ID,
      key = settings.P_APP_KEY,
      secret = settings.P_APP_KEY_SECRET,
      cluster = settings.P_REGION_CLUSTER,
      ssl = True
  )

  auth = pusher_client.authenticate(
      channel=request.query_params.get('channel_name'),
      socket_id=request.query_params.get('socket_id')
  )

  callback_query_params = request.query_params.get('callback')

  callback = re.sub(r'/\\"/g', '', callback_query_params) + "(" + str(auth) + ");";

  return Response(callback, content_type = 'application/javascript')
  • Here is the important part of the pusher connection in vue:
var pusher = new Pusher(env.pusher_app_key, {
      cluster: 'us2',
      authTransport: "jsonp",
      authEndpoint: "http://localhost:8000/pusher/auth",
    });

var channel = pusher.subscribe('private-cesar');

channel.bind('my-event', function(data) {
  console.log(data);
  this.messages.push(JSON.stringify(data));
});
  • Here is the python script I made to trigger the event manually:
import pusher

pusher_client = pusher.Pusher(
      app_id = settings.P_APP_ID,
      key = settings.P_APP_KEY,
      secret = settings.P_APP_KEY_SECRET,
      cluster = settings.P_REGION_CLUSTER,
      ssl = True
  )

  while True: 
      option = input("Send? (Y/N)") 
      if option.lower() == "y":
          pusher_client.trigger('private-cesar', 'my-event', {'message': 'test from python'}) 
          print("Sent")
      else:
          break

So, what seems to be the problem here, is there something I'm missing?

I already figured out how to use it without auth, And it works as expected, but in that case I don't need to have a auth/pusher endpoint.


Solution

  • SOLUTION:

    Finally, I solved this. Turns out I needed to return an HttpResponse object, which is provided by django.http, not the Response that rest_framework.response provides.

    My mistake: believing that rest_framework.response is implicit an http response.

    imports:

    from django.http import HttpResponse
    

    So the endpoint ended like this:

    def get(self, request):
            pusher_client = pusher.Pusher(
                app_id = settings.P_APP_ID,
                key = settings.P_APP_KEY,
                secret = settings.P_APP_KEY_SECRET,
                cluster = settings.P_REGION_CLUSTER,
                ssl = True
            )
    
            auth = pusher_client.authenticate(
                channel=request.query_params.get('channel_name'),
                socket_id=request.query_params.get('socket_id')
            )
    
            callback_query_params = request.query_params.get('callback')
    
            callback = re.sub(r'/\\"/g', '', callback_query_params) + "(" + str(auth) + ");";
    
            return HttpResponse(callback, content_type = 'application/javascript')