Authenticated and Unauthenticated Channels

I’m a Rails developer new to Phoenix. I would like to try a proof-of-concept stack with Phoenix.

The stack would be a Vue SPA, Flutter mobile app and Phoenix as the backend. I want to try to dump traditional REST API’s and have all data for the SPA and Mobile load via web sockets with a Phoenix channels.

Since all communication would occur over web sockets, I would need a socket connection that would handle unauthenticated tasks like login, sign up, forgot password, etc.

Once you are logged in, I would need a socket connection that is authenticated to perform user-related actions.

I basically have two questions.

  1. Is a socket-only approach a bad idea?

  2. If it is not, what would be the best practice for interacting with channels when some events will need to be authenticated and some will not. ie: login, signup, etc

Hello. I am working on a similar project for which i am considering using Elixir with Pheonix channels as it’s a chat based application. Perhaps we can collaborate and figure things out together.

Putting that aside you would want to use rest or graphql for the login and signup as sockets are really more for real time where you need an always open connection.

Ross

Hello and welcome,

You can create a public socket, and a private socket.

You can read more about this in the following book…

3 Likes

Thanks for the suggestion @kokolegorille. I just purchased the book on Kindle.

That’s a good point @rossedwards. I could use REST for signup/login. I wouldn’t need any real-time there. Hmmmm :thinking:

So what kind of application are you developing?

@rossedwards nothing in particular. Coming from Rails and just starting to learn Phoenix. Just a proof of concept exercise really.

I’m trying the approach of authenticating users in each channel’s join/3, but I want to avoid as much boilerplate code as possible.

I extracted a module that looks like this:

defmodule MyAppWeb.AuthorizedChannel do    
  defmacro __using__({:<>, _, [_topic_prefix, {var_name, _, _} = id_part]} = topic) do    
    quote location: :keep do    
      @impl true    
      def join(unquote(topic) = topic, payload, socket) do
        if socket.assigns[:current_user] do
          socket = assign(socket, unquote(var_name), unquote(id_part))    
          handle_post_join(topic, payload, socket)
        else
          {:error, %{status: "unauthorized"}}
        end                                                                                      
      end                                                                                                                             
                                                                                                                                      
      def handle_post_join(_topic, _payload, socket), do: {:ok, socket}    
      defoverridable handle_post_join: 3    
    end    
  end                                                                                                             
end   

and here’s how to use it:

defmodule MyAppWeb.FooChannel do
  use MyWebApp, :channel
  use MyWebApp.AuthorizedChannel, "foo:" <> foo_id

  def handle_post_join(_topic, _payload, socket) do
    {:ok, assign(socket, :foo, get_foo(socket.assigns.foo_id))}
  end

  # other stuff except `join/3`
end

Still struggling to fix the ugliness :sweat_smile:

Some nice code!

@dsalzr I am research elixir for 2 different projects. As i mentioned if you want to do some collaboration perhaps we can put a test project together. I am looking at using sockets as well as liveview for one of the projects.

1 Like

Always happy to help if you have any specific questions. If you’re just looking to get your feet wet, then I think that my book will be very helpful for you. Chapter 4 is of course going to be the prime chapter for authentication concerns.

I definitely still use and see the value of static forms and requests. User login and signup is a great example of a time that I’d use a plain ol controller/view.