User Authentication With The Phoenix Framework and Coherence

User Authentication With The Phoenix Framework and Coherence

Phoenix is a web framework built on Elixir. Coherence is a fully featured, configurable authentication system for Phoenix. In this post we'll discuss how to get setup and running with Coherence.

If you'd like to follow along check out my Github project.

Why Coherence?

Coherence is not the only authentication package for Phoenix. There are several others. You may even have heard one called Guardian. Guardian is an authentication package for Elixir and Phoenix. I haven't used it much although from what I can tell it's is very different then Coherence. Guardian uses JWT tokens while Coherence uses several authentication plugs like Sessions, HTTP basics and database session persistence.

Coherence has several modules that makes authentication easier to implement. See the list below. (This was taken from the GitHub page)

  • Database Authenticatable: handles hashing and storing an encrypted password in the database.
  • Invitable: sends invites to new users with a sign-up link, allowing the user to create their account with their own password.
  • Registerable allows anonymous users to register a users email address and password.
  • Confirmable: new accounts require clicking a link in a confirmation email.
  • Recoverable: provides a link to generate a password reset link with token expiry.
  • Trackable: saves login statistics like login counts, timestamps, and IP address for each user.
  • Lockable: locks an account when a specified number of failed sign-in attempts has been exceeded.
  • Unlockable With Token: provides a link to send yourself an unlock email.
  • Rememberable: provides persistent login with 'Remember me?' check box on login page.

After the plugin is installed in the phoenix project you can install any or all of the modules with mix coherence.install command. Coherence will install name spaced templates and views to make this process even easier. To check out how to use coherence run mix help coherence.install to see all the options available.

One last thing to remember is that Coherence is very new and is changing. I'll try to keep this blog updated as new changes are added. If all else fails check out the official Github page if you need help or feel free to leave a comment below!

Setup

We'll assume before we start that you have Erlang, Elixir, Node and Phoenix installed. If not, you can check out my last Phoenix post where I describe how to get started with Phoenix. You can also check out the official documentation too.

Let's begin by creating a new application called authExample.

$ mix phoenix.new authexample #press 'Y' to install deps
$ cd authexample
$ mix ecto.create

Make sure the ecto.migrate command runs without errors. If you see errors you may want to check out the database setup in config/dev.exs. Verify the login and password is correct.

Phoenix can generate boilerplate files for us, to make creating an application quicker. The phoenix.gen.html command creates a resource. This resource will include the schema, view, controller, migration file, templates and test files.

$ mix phoenix.gen.html Post posts title:string body:text

This command will create a resource called posts. We'll use this basic route to create, edit and delete posts, as if we were creating a blog application. We will first set it up without authentication, then we'll add authentication and see how that works.

Creating a Basic Post

(Without Authentication)

We need to update the router for our new post route.

// web/router.ex
...
 scope "/", Authexample do   
    pipe_through :browser # Use the default browser stack 
    resources "/posts", PostController 
    get "/", PageController, :index 
  end
...

In the Authexample "/" scope add the resources line. The resources macro adds eight clauses of the match/3 function. This will add all the HTTP verbs (GET, POST, PUT, DELETE, etc) for this new post route.

Next you'll need to run the migration.

$ mix ecto.migrate

This will add the posts table.

Let's take a look at our routes by running mix phoenix.routes.

Compiling 9 files (.ex)
Generated authexample2 app
post_path  GET     /posts           Authexample.PostController :index
post_path  GET     /posts/:id/edit  Authexample.PostController :edit
post_path  GET     /posts/new       Authexample.PostController :new
post_path  GET     /posts/:id       Authexample.PostController :show
post_path  POST    /posts           Authexample.PostController :create
post_path  PATCH   /posts/:id       Authexample.PostController :update
           PUT     /posts/:id       Authexample.PostController :update
post_path  DELETE  /posts/:id       Authexample.PostController :delete
page_path  GET     /                Authexample.PageController :index

As you can see these were all added by the resources macro we added into the route.

Fire up the web server and let's take a look!

$ mix phoenix.server

Look at the new posts route at http://localhost:4000/posts. This was all generated by Phoenix without much additional effort. Very neat!

<img src="/content/images/2017/01/Screen-Shot-2017-01-24-at-9.55.51-PM.png" style="max-width:100%;height:auto" align="middle""/>

Adding Authentication With Coherence

To get Coherence running lets install it in our mix file.

We'll need to add it to the application array first.

// mix.exs
...
     applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
                    :phoenix_ecto, :postgrex, :coherence]]

...

Next add it to our list of dependencies.

// mix.exs
...
  defp deps do
    [{:phoenix, "~> 1.2.1"},
     {:phoenix_pubsub, "~> 1.0"},    
     {:phoenix_ecto, "~> 3.0"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.6"},
     {:coherence, "~> 0.3"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:gettext, "~> 0.11"},
     {:cowboy, "~> 1.0"}]
  end
...

And now we can install our dependencies.

$ mix deps.get

At this point we have a choice. Ideally, we can just install the modules we want with coherence. For the purpose of this tutorial we'll use the --full-invitable argument. This will install all the modules except confirmable.

$ mix coherence.install --full-invitable

Let's create a protected route. In this example we want a protected route to redirect a user to the login page, if the user is not logged in. If the user logs in correctly they can then see the protected route. If they enter the incorrect password they get an error.

Let's make the posts route protected. Per the documentation we'll need to add the Coherence.Router, a few pipelines and some new scopes.

First let's add that Coherence router to the top of the file.

// web/router.ex
defmodule Authexample.Router do
  use Authexample.Web, :router 
  use Coherence.Router        #new Coherence Router
...

Adding the Coherence.Router will give us access to the routes Coherence created for us.

In the same file, add in the browser and protected pipeline (Remember to delete the existing browser pipeline first, or just add the Coherence.Authentication.Session to the bottom of it)

// web/router.ex
...
pipeline :browser do
    plug :accepts, ["html"]    
    plug :fetch_session        
    plug :fetch_flash          
    plug :protect_from_forgery 
    plug :put_secure_browser_headers
    plug Coherence.Authentication.Session  # Add this
  end

  pipeline :protected do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug Coherence.Authentication.Session, protected: true
  end
...

Next add these scopes.

// web/router.ex
...
  # Add this block
  scope "/" do
    pipe_through :browser
    coherence_routes
  end

  # Add this block
  scope "/" do
    pipe_through :protected
    coherence_routes :protected
  end
...

Finally we can now add a new protected route to posts. Delete the resources macro out of the AuthExample "/" scope and add it to a new protected scope.

// web/router.ex
...
  scope "/", Authexample do    
    pipe_through :protected # Use the default browser stack 
    resources "/posts",PostController
  end
...

This will protect the posts route and by convention will redirect the user to one of the built in routes we just created with coherence if the user isn't logged in. (You can check out all the routes Coherence created by running mix phoenix.routes)

The home page will not be changed and will not require a login.

The last thing we need to do is seed our database. Since we are using database authentication let's add a new Test user.

// priv/repo/seeds.exs
Authexample.Repo.delete_all Authexample.User

Authexample.User.changeset(%Authexample.User{}, %{name: "Test User", email: "testuser@example.com", password: "secret", password_confirmation: "secret"})
|> Authexample.Repo.insert!

Before we run this let's make sure that all our migrations have been run.

$ mix ecto.migrate

This will make sure that all our tables have been created, including the user one for authentication.

Run this command to seed the database with our new test user. (If you run into any errors make sure that you didn't change the application name otherwise the changeset will fail. The names must match)

$ mix run priv/repo/seeds.exs

There it is! Let's fire up the app and see if it works!

$ mix phoenix.server

Head over to http://localhost:4000/posts.

Now it wants us to login! Put in our test user information, and try to login. (Email: testuser@example.com Password: secret)

<img src="/content/images/2017/01/Screen-Shot-2017-01-24-at-10.34.38-PM.png" style="max-width:100%;height:auto" align="middle""/>

That's it we are in!

Conclusion

In this tutorial showed how easy it is getting started with Coherence. There is a lot more we could do. If you like, try to implement a logout button and try out the "Need An Account" button. See how it works!

Take care! If you like this post and you want to learn more, sign up below to get on my list. I'm constantly sending out tips and tricks on the latest frameworks! Thanks!