Authentication and Authorization in Phoenix Live View
By: Hari Roshan
Tags: Liveview, Phoenix Framework, Elixir, Authentication, Phoenix Liveview

Let’s start with a simple Signup User Ecto.Schema. (I assume you know how to setup Live View. If not create a project with the following command )

mix phx.new management --live

Create a module to generate tokens

Now that we have the schema and token generation modules, we can write interface functions in the context module

We will create a SignupLive which will handle the registration process. For that, Create signup_live.ex and signup_live.html.leex.

In the leex file, add the following code. I have used Bulma css and Font awesome but you can remove the unnecessary code and keep the minimum form fields

In the signup_live.ex add the following contents. The code should be self explanatory, but I’ll explain clearly below.

In the mount/3 callback, we are fetching the changeset from the Accounts context module to render the form.

The form will emit 2 events.

validate — It is emitted when input field is blurred. So we are only validating the params with the changeset with the help of Accounts.check_registration/1 . In the Accounts.check_registration/1 , changeset action is updated to :insert . Without this, you will not see any errors in the form save — It is emitted when the user clicks the submit button. We use this to insert the data into the database. If it fails due to database constraint errors, then we will render the changeset with errors.

If the insert is successful, We will use the Accounts.sign(ManagementWeb.Endpoint, user.id) to create a token and redirect to Routes.session_path(socket, :create, token)

We haven’t created the controller yet. So, we will create a controller with the filename session_contoller.ex under the controller directory

In the SessionController, create the following method. We have received the token from the SignupLive process. We can verify the token and fetch user_id from the token. Now, we will create a new token with different expiry which will be stored the browser session store.

_________________________________ Example: Auth.login

_________________________________ def login(conn, user_id, remember_me \\ false) do

conn

|> put_session(:token, Accounts.sign(conn, user_id))

|> put_session(:remember_me, remember_me)

|> configure_session(renew: true)

end __________________________________ def create(conn, %{"token" => token} = params) do case Accounts.verify(ManagementWeb.Endpoint, token) do

{:ok, user_id} ->

conn

|> Auth.login(user_id)

|> redirect(to: Routes.page_path(conn, :index)) _ -> create(conn, params)

end

end def create(conn, _params) do

conn

|> put_flash(:error, "error")

|> redirect(to: Routes.signup_path(conn, :index))

end



Finally, lets add get “/session/:token”, SessionController, :create in the router.

After the token has been assigned in the browser session, All the liveview mounts/3 and handle_event/3 will receive %{“token” => token} like so

mount(_params, %{“token” => token}, socket) which we can verify using Accounts.verify/3 to check the validity and get the user_id inside the LiveView. The same procedure can be used to perform Login as well.

It is better to write a plug to protect the protected routes than verifying the token in every LiveView.

I hope it helps. Thanks