Sending a message to a user/socket on_connect (without a channel)

I have an application where a user connects to a socket by sending a user_id, password, and tenant_name which is then checked against a database. If creds are valid the socket connection is accepted and they can connect to channels using a tenant_uuid. However, the client does not know this uuid so I would like for it to be sent over the socket to the user after successful connection.

I think I could do this by adding a Channel user’s can connect to using their user_id and then broadcasting a message with the tenant_uuid to them upon channel connect but I wanted to try and do this without a channel.

I was able to piece something together that works by overriding the Phoenix.Socket init/1 method but not sure if it is either too hacky or will cause some weird issues. Here’s the code:

Server

defmodule MyAppWeb.UserSocket do
  use Phoenix.Socket

  defoverridable init: 1

  # Send the tenant_uuid back to the client socket on connection. Out of the box Phoenix
  # does not provide a way to send a message directly to a socket/individual user (unless
  # you subscribe the user to a private topic, i.e topic "user"<>user_id)
  # Given that we are overriding the init which is called after successful connect.
  # At this stage the transport_pid has been set and the socket.assigns have also been set.
  # The format of the message sent to the user is in the expected format for the Phoenix client js
  # library to successfully parse the message so we can handle it.
  @impl true
  def init(state) do
    response = {:ok, {_, %{transport_pid: transport_pid} = socket}} = super(state)
    # Parsed on client side, expected format is:
    #   [join_ref, ref, topic, event, payload]
    message = ~s(["","","","tenant_uuid_sent",{"tenant_uuid":"#{socket.assigns.token_data.tenant_uuid}"}])
    send(transport_pid, {:socket_push, :text, message})
    response
  end

 @impl true
  def connect(
        %{"user_id" => user_id, "password" => password, "tenant_name" => tenant_name},
        socket,
        _connect_info
      ) do
    case Users.login(user_id, password, tenant_name) do
      {:ok, %{token: token, token_data: token_data}} ->
        Logger.info("New socket connection from #{token_data.user_id}")
        {:ok, assign(socket, token_data: token_data, token: token)}

      _ ->
        Logger.error("#{__MODULE__}: Connection error - verification failed")
        :error
    end
  end

Client (javascript)

let socket = new Socket({ params : { user_id: "....", password: "....", tenant_name: "..." } });
let channel;
socket.onMessage((message) => {
      if (message.event == 'tenant_uuid_sent') {
        tenantUUID = message.payload.tenant_uuid;
        channel = socket.channel(`events:${tenantUUID}`);
        channel.join();
    });
socket.connect();