Phauxth is an authentication library for Phoenix (> 1.3), or other Plug-based, web applications.

It is designed to be secure, extensible and well-documented. Rather than offering many ‘features’, its focus is on providing building blocks to help with authentication.

Phauxth offers two kinds of functions, plugs and verify/3 functions. This post looks at the basic use of these two and also how they can be extended to create custom authentication functions.

For more information about using Phauxth, see the wiki or the docs.

Plugs - Phauxth.Authenticate and Phauxth.Remember

By default, Phauxth.Authenticate checks the conn (connection) struct for a current session, authenticates the user based on the session information, and then adds the user information to assigns.current_user in the conn.

It also prints out a log message stating if authentication was successful or not.

This function is usually added to the pipeline you want to authenticate in the router.ex file, as in the following example:

pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session
  plug :fetch_flash
  plug :protect_from_forgery
  plug :put_secure_browser_headers
  plug Phauxth.Authenticate
end

If you call Phauxth.Authenticate with the method: :token option, it will look for a token in the request headers and use that token to authenticate the user. Here is an example of using this option with an api (in the router.ex file):

pipeline :api do
  plug :accepts, ["json"]
  plug Phauxth.Authenticate, method: :token
end

Extending Phauxth.Authenticate

One example of extending Phauxth.Authenticate is the Phauxth.Remember plug, which provides the ‘remember me’ functionality and is included in the Phauxth library.

We will look at two more examples next - using a different session / token implementation and using Phauxth with Absinthe (GraphQL). Both these examples need to be called with the method: :token option shown above.

Using a custom session / token implementation

To use a custom session / token implementation, you need to override the check_session or check_token function. The example below shows an example of overriding check_token to use a different token implementation, such as JSON Web Tokens, instead.

defmodule CustomAuthenticate do
  use Phauxth.Authenticate.Base
  import Plug.Conn

  def check_token(conn, token, max_age, opts) do
    custom_token_verify(conn, token, max_age, opts)
  end
end

Using Absinthe / GraphQL

In this example, we just need to override the set_user function so that Absinthe can find the current user information.

defmodule AbsintheAuthenticate do
  use Phauxth.Authenticate.Base
  import Plug.Conn

  def set_user(user, conn) do
    put_private(conn, :absinthe, %{token: %{current_user: user}})
  end
end

Verify/3 - Phauxth.Login.verify and Phauxth.Confirm.verify

Each verify function takes three arguments, params, the user context module name and options (an empty list by default), and it returns {:ok, user} or {:error, message}.

In the example below, Phauxth.Login.verify is called within the create function in the session controller.

def create(conn, %{"session" => params}) do
  case Phauxth.Login.verify(params, MyApp.Accounts) do
    {:ok, user} -> handle_successful_login
    {:error, message} -> handle_error
  end
end

In this example, the user’s password will be checked with Comeonin.Bcrypt. If you want to use a different algorithm, use the crypto option:

Phauxth.Login.verify(params, MyApp.Accounts, crypto: Comeonin.Argon2)

Phauxth.Confirm.verify is used for user confirmation and for password resetting. See the documentation for examples and more information. I will look at this function in more detail in a separate post.

Extending Phauxth.Login.verify

One example of extending Phauxth.Login.verify can be seen in the Phauxth.Confirm.Login module, which is shown below. By overriding the check_pass function, the verify function now checks if the user account has been confirmed before verifying the password.

defmodule Phauxth.Confirm.Login do
  use Phauxth.Login.Base

  def check_pass(%{confirmed_at: nil}, _, _, _), do: {:error, "account unconfirmed"}
  def check_pass(user, password, crypto, opts) do
    super(user, password, crypto, opts)
  end
end

This function is called in the same way as Phauxth.Login.verify:

Phauxth.Confirm.Login.verify(params, MyApp.Accounts)

As for further examples, those are for you to write!