guide, elixir, phoenix, pow, authentication

Add Authentication to Phoenix with Pow

Working with Rails for many years, we've become a little spoiled when it comes to authentication given the vast number of mature libraries available .   Phoenix has few options to choose from and some of the libraries are no longer maintained.  

We were happy to find that @danschultzer  was kind enough to build a powerful and flexible auth system for Phoenix called Pow.

Pow is a robust, modular, and extendable authentication and user management solution for Phoenix and Plug-based apps.

Overview

In this guide we're going to install Pow on a greenfield app, set up email confirmation and password resetting.

Pre-requisites

  • Your local development environment ready for Phoenix Development.
  • Some knowledge of how to work with Elixir Phoenix applications.

Create a new Phoenix App

Let's start by creating a new app:

$ mix phx.new phx_pow  

...

Fetch and install dependencies? [Yn] 

And hit enter to install things.

Then the usual commands:

$ cd phx_pow

$ mix ecto.create

Add Pow Configuration

Open mix.exs and add this line to deps:

defp deps do
  [
    # ...
    {:pow, "~> 1.0.13"} # use current version from docs
  ]
end

Run mix deps.get to install it.

Next, run:

$ mix pow.install

This will add the following files to your app:

LIB_PATH/users/user.ex
PRIV_PATH/repo/migrations/TIMESTAMP_create_user.ex

Add the following to config/config.exs:

config :phx_pow, :pow,
  user: PhxPow.Users.User,
  repo: PhxPow.Repo

Set up WEB_PATH/endpoint.ex to enable session based authentication (Pow.Plug.Session is added after Plug.Session):

defmodule PhxPow.Endpoint do
  use Phoenix.Endpoint, otp_app: :phx_pow

  # ...

  plug Plug.Session,
    store: :cookie,
    key: "...",
    signing_salt: "..."

  # add this below

  plug Pow.Plug.Session, otp_app: :phx_pow

  # ...
end

Add Pow routes to WEB_PATH/router.ex:

defmodule PhxPowWeb.Router do  
  use PhxPowWeb, :router    
  use Pow.Phoenix.Router  # --- Added

  # ... pipelines

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

  scope "/" do
    pipe_through :browser

    pow_routes()
  end

  scope "/", MyAppWeb do
    pipe_through [:browser, :protected]

    # Add your protected routes here
  end

  # ... routes
end

That should do it for the main configuration.

Run:

$ mix ecto.setup

To run the migrations and complete the setup.

$ mix phx.server

And you can now visit http://localhost:4000/registration/new, and create a new user.

Add Extensions for Email Actions

We're going to install the extensions  PowResetPassword and PowEmailConfirmation.

First let's create the migrations needed using Pow's generators:

$ mix pow.extension.ecto.gen.migrations --extension PowResetPassword --extension PowEmailConfirmation

And run the migrations with:

$ mix ecto.migrate

Next open config/config.exs and update the pow config, adding extensions  controller_callbacks, and web_module configuration:

config :phx_pow, :pow,
  user: PhxPow.Users.User,
  repo: PhxPow.Repo,
  extensions: [PowResetPassword, PowEmailConfirmation],
  controller_callbacks: Pow.Extension.Phoenix.ControllerCallbacks,
  web_module: PhxPowWeb 

Update LIB_PATH/users/user.ex with the extensions:

defmodule PhxPow.Users.User do
  use Ecto.Schema
  use Pow.Ecto.Schema
  use Pow.Extension.Ecto.Schema,
    extensions: [PowResetPassword, PowEmailConfirmation]

  # ...

  def changeset(user_or_changeset, attrs) do
    user_or_changeset
    |> pow_changeset(attrs)
    |> pow_extension_changeset(attrs)
  end
end

Now add Pow extension routes to WEB_PATH/router.ex (note the :otp_app configuration that will pull the extensions defined in the app environment):

defmodule PhxPowWeb.Router do
  use PhxPowWeb, :router
  use Pow.Phoenix.Router
  use Pow.Extension.Phoenix.Router, otp_app: :phx_pow

  # ...

  scope "/" do
    pipe_through :browser

    pow_routes()
    pow_extension_routes()
  end

  # ...
end

Generate Extension Templates

Similar to Devise, templates and views for the extensions can be generated:

$ mix pow.extension.phoenix.gen.templates --extension PowResetPassword --extension PowEmailConfirmation

* creating lib/phx_pow_web/views/pow_reset_password/reset_password_view.ex
* creating lib/phx_pow_web/templates/pow_reset_password/reset_password/new.html.eex
* creating lib/phx_pow_web/templates/pow_reset_password/reset_password/edit.html.eex

Generate General Pow Views

While we're at it, let's generate all the views for sessions and registrations:

$ mix pow.phoenix.gen.templates

* creating lib/phx_pow_web/views/pow/registration_view.ex
* creating lib/phx_pow_web/templates/pow/registration/new.html.eex
* creating lib/phx_pow_web/templates/pow/registration/edit.html.eex
* creating lib/phx_pow_web/views/pow/session_view.ex
* creating lib/phx_pow_web/templates/pow/session/new.html.eex

Now you're able to customize the views for the auth pages similar to Devise.

Conclusion

This wraps up an introductory guide on adding authentication to Elixir Phoenix using Pow.   Pow is an actively developed and maintained library and will likely remain this way for the foreseeable future.

We have installed and configured Pow and a few of its extensions, and have a mostly functional authentication system going.

In the next guide, we're going to add Mailer support using sendgrid and another great library called Bamboo by ThoughtBot.

Follow us on Twitter for updates: @phxroad

Resources

Update

Author image

About Troy Martin

Husband, Father & Software Developer who tinkers with writing and building things.
  • Hamilton, ON