Dev Series – Phoenix Part 2 – Authentication using Pow


Phoenix Elixir PostgreSQL
tutorial phoenix authentication pow security

Dev Series – Phoenix Part 2 – Authentication using Pow

Published at June 27, 2021

Last week we have set up our basic application, in this tutorial, I will guide you through setting up user authentication using Pow, a powerful library for user authentication.

ADDING THE PACKAGE

First, let’s add Pow to our dependencies in mix.exs:

{:pow, "~> 1.0"}

Run the following commands to install the dependency:

mix deps.get

After adding the package, let’s install Pow by running the following command. This installs a user schema and migration file that you can use for your basic authentication, registration, and password reset functionality.

mix pow.install

After running the command, you should see the following output:

* creating lib/repz_exercise/users/user.ex
* creating priv/repo/migrations/20210627000000_create_users.ex

Add the following to config/config.exs:

config :repz_exercise, :pow,
  user: RepzExercise.Users.User,
  repo: RepzExercise.Repo

Remember to update your repository by running migrations:

$ mix ecto.migrate

Once done add the config to your config/config.exs:

config :repz_exercise, :pow,
  user: RepzExercise.Users.User,
  repo: RepzExercise.Repo

Let’s also run the migration:

mix ecto.migrate

Let’s also add the plug to the browser pipeline:

pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session
  plug :fetch_live_flash
  plug :put_root_layout, {RepzExerciseWeb.LayoutView, :root}
  plug :protect_from_forgery
  plug :put_secure_browser_headers
  plug Pow.Plug.Session, otp_app: :repz_exercise
end

Once done add the routes and configure the protected routes:

defmodule RepzExerciseWeb.Router do
  use RepzExerciseWeb, :router
  use Pow.Phoenix.Router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, {RepzExerciseWeb.LayoutView, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug Pow.Plug.Session, otp_app: :repz_exercise
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  pipeline :protected do
    plug Pow.Plug.RequireAuthenticated,
      error_handler: Pow.Phoenix.PlugErrorHandler
  end

  scope "/" do
    pipe_through :browser

    pow_routes()
  end

  scope "/", RepzExerciseWeb do
    pipe_through :browser

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  # scope "/api", RepzExerciseWeb do
  #   pipe_through :api
  # end
end

Let’s also add the current user to the connection assigns. Add this to your router:

pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session
  plug :fetch_live_flash
  plug :put_root_layout, {RepzExerciseWeb.LayoutView, :root}
  plug :protect_from_forgery
  plug :put_secure_browser_headers
  plug Pow.Plug.Session, otp_app: :repz_exercise
  plug :assign_current_user
end

defp assign_current_user(conn, _opts) do
  assign(conn, :current_user, Pow.Plug.current_user(conn))
end

Let’s also add the authentication links to our layout. Update your app.html.eex:

<header>
  <section class="container">
    <nav role="navigation">
      <ul>
        <li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
        <%= if @current_user do %>
          <li>Welcome <%= @current_user.email %></li>
          <li><%= link "Sign out", to: Routes.pow_session_path(@conn, :delete), method: :delete %></li>
        <% else %>
          <li><%= link "Register", to: Routes.pow_registration_path(@conn, :new) %></li>
          <li><%= link "Sign in", to: Routes.pow_session_path(@conn, :new) %></li>
        <% end %>
      </ul>
    </nav>
    <a href="https://phoenixframework.org/" class="phx-logo">
      <img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" alt="Phoenix Framework Logo"/>
    </a>
  </section>
</header>

Let’s start our server and check if everything is working:

mix phx.server

Let’s also add a link to the home page:

<%= link "Home", to: Routes.page_path(@conn, :index) %>

SUMMARY

Great! Now we have set up authentication in our Phoenix. It is painless and straightforward. We can now implement user-specific features like user can only see and edit their own data.

Next week we will implement our first feature.

Cheers and Coding!