Does Frappe’s default socket.io server allow external service connections?

Hi everyone,
I have a question regarding the default socket.io server that comes with Frappe. By default, does Frappe allow socket connections from external services (not just the browser or the same origin)? I want to connect socket to listen event push realtime from backend using Flutter App.

If external connections are supported, what is the correct way to configure and authenticate them?

Thanks in advance!

Yes
Check this Realtime (socket.io)

Also check Raven they built a react native chat app so that definitely suits your use case

1 Like

Thank you for your support. I’ve reviewed the Frappe Raven source code as well as some of Frappe’s official documentation. It seems that connecting to the Socket.IO server is technically possible, but I frequently encounter the “Invalid origin” error.

Looking into Frappe’s core, I found this section:

if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin)) {
    next(new Error("Invalid origin"));
    return;
}

This makes me wonder whether Frappe is intentionally blocking connections from external origins.

With Frappe Raven, it uses a React-based client. When specifying the sitename and token in the config and using the websocket transport, I was able to connect successfully with http://localhost:9000. However, it seems that the sitename parameter has no actual effect. Additionally, even when I publish a realtime event without specifying any user, no messages are received on the client.

Oh right,
I faced the same issue when I was setting up Staging environments via Dokploy and the only way I figured was to patch the middleware. I added it as a separate volume so that even when you pull frappe updates you can redeploy to patch it.

That version also patched utils.js but for you I only think you need authenticate.js, something like this:

patch-socketio:
  image: frappe/bench:latest
  command:
    - bash
    - -c
    - |
      echo 'Waiting for bench initialization...'
      until [ -f /home/frappe/frappe-bench/apps/frappe/socketio.js ]; do
        sleep 5
      done
      
      cd /home/frappe/frappe-bench/apps/frappe/realtime
      
      # Backup original if not already done
      if [ ! -f middlewares/authenticate.js.original ]; then
        cp middlewares/authenticate.js middlewares/authenticate.js.original
      fi
      
      # Comment out the origin check
      sed -i 's/if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin))/if (false \&\& get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin))/' middlewares/authenticate.js
      
      echo 'Origin check disabled for external frontend access!'
  volumes:
    - frappe-home:/home/frappe
  depends_on:
    init-bench:
      condition: service_completed_successfully
  networks:
    - frappe-network
  restart: "no"
1 Like

I tried your suggestion. While the Invalid Origin error is gone, a new issue appeared: Unauthorized: Not Found.
After digging deeper into Frappe’s authenticate.js, I realized that Frappe is currently interpreting the socket parameter of authenticate_with_frappe(socket, next) as if the incoming connection were an internal URL. The evidence is in the line get_url(socket, "/api/method/frappe.realtime.get_user_info"). When the error is logged, it clearly shows that Frappe is building the URL using the client-supplied Host header — for example:

https://firecamp.dev/api/method/frappe.realtime.get_user_info

This obviously isn’t the actual domain of my Frappe site; it’s the domain of the testing tool.
So to allow an external application to use Frappe’s realtime socket functionality in the same way the built-in Frappe frontend does, we need to adjust how Frappe interprets the socket’s host/origin information — or override the logic that constructs the authentication URL?

On the Raven mobile app, we use OAuth bearer tokens to authenticate the user. If you use OAuth or API Key/Secret, it should bypass the host validation - atleast on latest versions of Frappe (latest v15 or above). We fixed this issue when building the mobile app.

1 Like