Index

House Keeping

There has been a ridiculous gap between the last post, and this one. During this gap a number of things have happened:

  1. Our daughter was born! :)
  2. I started working with a new company (in Elixir!)
  3. We moved to Barranquilla, Colombia (from Medellin) and are preparing to once again hop, this time back to Toronto (where I was born and raised)
  4. More frustrations on current editor (Vim/Emacs)
  5. I started learning Clojure (quite possibly the most fun I’ve had for a long time.)
  6. Other personal projects

At any rate, I do apologize for this. I would like to say that it won’t happen again, however, I know that moving back to Canada will once again throw me off my flow for a while…

Now that that is out of the way (must be a better way to say that that…) let’s get started.

Coherence

So, the last tutorial was on Phauxth which is great, but if you are looking for a more “batteries included” option - look no further! Coherence has two important things going for it (IMHO) it has a large user base and it is very simple to get up and running, so this tutorial should be a breeze.

Setup

Setting up an app is pretty straight forward. Once you have created your phoenix application (I just created a simple blog as before mix phx.new blog_coh) do the following:

  1. Add dependency:
    def deps do
     [{:coherence, "~> 0.5"}]
    end
    
  2. Make sure it is started:
    def application do
     extra_applications: [:logger, :runtime_tools, :coherence]
    end
    
  3. Install the dependencies with mix deps.get then mix deps.compile
  4. Change your router file as follows:
defmodule BlogCohWeb.Router do
  use BlogCohWeb, :router
  use Coherence.Router

  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
  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

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

  scope "/" do
    pipe_through :browser
    coherence_routes()
  end

  scope "/" do
    pipe_through :protected
    coherence_routes :protected
  end

  scope "/", BlogCohWeb do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
	# For public routes
  end

  scope "/", BlogCohWeb do
    pipe_through :protected
	# For private routes
  end

  # Other scopes may use custom stacks.
  # scope "/api", BlogCohWeb do
  #   pipe_through :api
  # end
end
  1. And lastly, run mix coh.install --full

There is one point of interest I should address before moving forward, Coherence has a few options you should be aware of. We used the “–full” option which installs all options except “confirmable” and “invitable”. I chose this as it is quick and shows off some features that Coherence includes to get you running very quickly, however there are several other options you should be aware of:

  • ”–install” by itself just adds authenticable option (no registration routes)
  • ”–full-confirmable” adds the functionality to send confirmation emails to users upon registration
  • ”–full-invitable” adds functionality to invite users
  • Additionally there are the “–rememberable”, “–lockable”, and “–trackable” flags. You can read more at Coherence Github Page

You can also read through the lib/blog_coh/coherence/user.ex file to see what the schema produced or the priv/repo/migrations/<date_stamp>_create_coherence_user.exs file to see what a more thorough representation of the schema. You may notice that lockable, trackable, and recoverable were added with the “full” option we chose.

One final thing I like to do for convenience is edit the seeds file priv/repo/seeds.exs as coherence suggests:

BlogCoh.Repo.delete_all BlogCoh.Coherence.User

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

Which will remove all previous users, and add one to use for testing/development.

This is the point where we should add any additional customization that we may need, if not go ahead and run: mix ecto.setup which will create the database if it does not exist, run the migrations, and our seeds file.

At the time of writing I received an error:

== Compilation error in file lib/blog_coh_web/coherence_messages.ex ==
** (ArgumentError) *gettext macros expect translation keys (msgid and msgid_plural) and
domains to expand to strings at compile-time, but the given msgid
doesn't.

Dynamic translations should be avoided as they limit gettext's
ability to extract translations from your source code. If you are
sure you need dynamic lookup, you can use the functions in the Gettext
module:

    string = "hello world"
    Gettext.gettext(BlogCohWeb.Gettext, string)

    (gettext) lib/gettext/compiler.ex:213: Gettext.Compiler.expand_to_binary/4
    expanding macro: BlogCohWeb.Gettext.dgettext_noop/2
    lib/blog_coh_web/coherence_messages.ex:75: BlogCohWeb.Coherence.Messages.you_are_using_an_invalid_security_token/0
    expanding macro: BlogCohWeb.Gettext.dgettext/2
    lib/blog_coh_web/coherence_messages.ex:75: BlogCohWeb.Coherence.Messages.you_are_using_an_invalid_security_token/0
    (elixir) lib/kernel/parallel_compiler.ex:198: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

A quick google search was able to resolve this, if you do see this change your gettext dependency to {:getext "0.13.1"}

Ready

You are not alone in thinking that was a lot of setup and indeed mystery going on. I personally try to avoid packages like this, as I think it will take less time to write the functionality I need then read through everything going on and keep up with problems that are inevitable to a package of this side, however there is no denying its attractiveness and I can see how someone would like to use a package like this to get going.

So what did all that get you? Let’s find out! Run mix phx.server then, navigate to localhost:4000/sessions/new and enter the email and password you setup in your seeds file. You will be redirected to the home link. Well, that isn’t much. Let’s add some private route and check that authentication is indeed working. Go to your PageController lib/blog_coh_web/controllers/page_controller.ex and add this route:

def ppage(conn, _params) do
	render conn, "ppage.html"
end

And of course create the template in lib/blog_coh_web/templates/page/ppage.html.eex and add some random stuff:

<h2>You are accessing a private route!</h2>

Add the route to your routes file in the protected routes scope:

scope "/", BlogCohWeb do
	pipe_through :protected
	get "/private", PageController, :ppage
end

Restart the server, and navigate to localhost:4000/private you should be redirected to login. Enter your login information and voila! You now have access to that private route.

Conclusion

Of course, this was just the tip of the iceberg. As this series is merely comparing three frameworks and detailing how to get started, I just wanted to quickly show you how to get to a jump off point. You can read up on Coherence github page for more details, or their source to really get your head around what’s going on. Like I previously stated, this is a very popular package and well maintained. I suppose I do not like it as it clashes with some of my ideas around how a package should behave (get the bloody hell out the way, or be perfectly transparent) and I do not think the functionality justifies the labour in terms of digging through their code to see what is going on. Phoenix is the framework I am using, but coherence feels like a mini-framework on top of that, and if that is something you like, great many people do, I am just not one of them. I of course mean no offense to the maintainers of Coherence, the code is well written, they are active, etc. In fact I think it would be of great value to peruse the code base and wrap your ahead around how they choose to implement authentication. Cheers!