User registration and session management is a very common feature of any non-trivial web application. A custom solution is always an option and is usually pretty easy to implement. This is certainly the case when working with Phoenix, and there are many books and online tutorials that step thru the process of building out a custom authentication solution.
Although not difficult, this can get pretty involved, especially when adding typical features such as registration confirmation, password reset, and session persistence.
Recently I stumbled across Pow… as per the GitHub description, Pow
is: “a robust, modular, and extendable authentication and user management solution for Phoenix and Plug-based apps”.
The Pow
README
section is pretty comprehensive, providing a good description of how to get things up and running. However, I figured a step-by-step tutorial might still be useful, so let’s Pow
er up (ha, ha) and see how it works!
What we’ll build
For the purposes of demonstrating how to use Pow
we will be building a very bare bones Phoenix application. We won’t worry about making it look pretty or customizing it in any way, but we will use a generator to create some pages we want to secure with Pow
, just to demonstrate how that functionality works.
I’d encourage you to follow along, but if you want to skip directly to the code, it’s available on GitHub at: https://github.com/riebeekn/phx-auth-with-pow.
So let’s get at it!
Creating our app
Our first step is to create our application, we’ll pretend we are building out a basic (super, super, basic) warehouse inventory system, so we’ll call our application warehouse
.
Terminal
Choose Y
when asked to fetch and install dependencies. Now we’ll change into the application directory and create the database.
Terminal
We’ll want to demonstrate how to secure pages when using Pow
, so let’s use a generator to create our “inventory” context and our “product” pages. We’ll look to restrict access to these pages, only allowing logged in users to view them.
Terminal
As per the mix
output, let’s run the migrations…
Terminal
… and update the routes.
/lib/warehouse_web/router.ex …line 16
Let’s also add a link in the header for navigating to the main products page where we list our products.
/lib/warehouse_web/templates/layout/app.html.eex …line 11
That is pretty much it as far as our application functionality goes so let’s fire up the application and see what we got.
Terminal
If we navigate to http://localhost:4000/ we’ll see the standard Phoenix landing page, and the Products link will take us to the main Products page.
So with a very basic application in place, let’s see how we can add user authentication and management to our application via Pow
.
Using Pow within our application
There are a number of options and extensions available to us when using Pow
but we’ll start with a basic installation, and go from there.
Basic Installation
The first step is to add pow
to our list of dependencies.
/mix.exs …line 34
Now we need to grab our dependencies via mix deps.get
.
Terminal
The mix
output will indicate that pow
has been added to our application.
Next we need to install Pow
.
Terminal
Now we need to deal with a bit of configuration.
Configuration
First update config.ex
, adding a new configuration section for Pow
. I’ve placed this above the logger configuration.
/config/config.exs
Next we need to update endpoint.ex
.
/lib/warehouse_web/endpoint.ex …line 40
We’ve added a pow
specific plug directly after the session plug.
That’s it for configuration, we now need to add some routes.
Route updates
There are some Pow
specific routes we need to add, and we also need a specific pipeline for protected resources.
/lib/warehouse_web/routes.ex
So we’ve added a new use
statement for the Pow
routes (use Pow.Phoenix.Router
); a new pipeline; and two new scopes. We can see that the second scope is where our protected routes should be going.
Running migrations
Finally, when we installed Pow
, a new migration file was created, so we also need to run migrations.
Terminal
Using TablePlus we can view the structure of the users
table created for us by Pow
.
Looks good!
Updating the navigation links
Before we run our application let’s have a look at our routes.
Terminal
Pow
has made available a number of new routes for us.
Let’s update our navigation to include links to relevent routes. We also now have access to a current_user
variable, so can display appropriate links based on whether a user is currently logged in or not.
We’ll always display the Products
link… just to make it easy to test whether it has been properly protected.
/lib/warehouse_web/templates/layout/app.html.eex …line 13
Ok, with all these changes in place let’s start our server back up and see how things are looking.
Checking out the Pow functionality
Terminal
Our new links are appearing in the header.
Following the sign up
link we see the registration page Pow
creates for us:
After signing up, we are automatically signed in.
We now have access to pages that are specific to signed in users, such as the “Edit profile / account” page.
If we sign-out we’ll see that despite being signed out we can still access the products
page.
Let’s secure the page by updating our routes.
/lib/warehouse_web/router.ex …line 29
We’ve removed the ‘products’ resources from the lower scope and placed them in the protected scope. Clicking the Products
link now re-directs to the sign in page.
Customizing the Pow templates
So this is pretty sweet! We have a good amount of functionality and it’s required very little effort or set-up.
What if we’re not happy with the templates Pow
creates however? Before stopping for the day, let’s see how easy it is to customize the Pow
templates.
The first step is to generate the templates.
Terminal
We then need to update config.exs
to indicate we want to use the generated templates.
/config/config.exs …line 20
We’ve added the web_module
value, and we can now update the templates in lib/warehouse_web/templates/pow
and we’ll see our changes reflected in our application. Changing the configuration requires a server restart, so let’s restart our server.
Terminal
And then make a few small changes to the Pow
templates.
/lib/warehouse_web/templates/pow/session/new.html.eex …line 18
We’ve updated the text to read Sign in now!
, and this get’s reflected in our application.
A pretty trivial change, something that might make a bit more sense is adding a “Close account” link to the edit profile page.
/lib/warehouse_web/templates/pow/registration/edit.html.eex …line 26
And voila, user’s now have a way to close out their account.
If we ever want to revert to the default templates, we can just remove the config.exs
web_module
entry.
/config/config.exs …line 20
After a server restart, we’re back to our original templates.
I like having that “Close account” available on the Edit page however, so let’s switch the configuration back to include web_module: WarehouseWeb
.
/config/config.exs …line 20
A quick word about tests
I haven’t been sure how to handle testing for the purposes of this post. Testing is obviously very important but at the same time can require a fair bit of explanation which can add significantly to the length of a post and distract from the core subject.
Initially I was going to completely ignore testing, and indeed if you run mix test
you’ll see a number of tests will fail with the updates we’ve made to the code base.
This felt a little janky… so as a compromise I’ve updated the existing tests in the master branch of the GitHub repo so they pass; but there is no discussion of the tests (as you’ve no doubt noticed) and I haven’t added any new tests. Needless to say, with a real application this is not the strategy you would want to follow!
Summary
That’s all for today, the bare bones behaviour provided by Pow
is pretty impressive, especially considering how easy it is to get set up. There is more goodness on the horizon however, next time we’ll look at how easy it is to add session persistence, registration confirmations and forgot password functionality.
Thanks for reading and I hope you enjoyed the post!