Authenticator 
This module provides the glue for authenticating HTTP requests.
By using Authenticator
, you’ll get the following functions:
sign_in(conn, user)
- Sign a user in.sign_out(conn)
- Sign a user out.signed_in?(conn)
- Check if a user is signed in.
You’ll also get the following plugs:
Authenticator.Session
- Authenticate a user from the session.Authenticator.Header
- Authenticate a user from theAuthorization
header.Authenticator.Authenticated
- Make sure a user is signed in.Authenticator.Unauthenticated
- Make sure a user is not signed in.
Installation
The package can be installed by adding authenticator
to your list of dependencies in mix.exs
:
def deps do
[{:authenticator, "~> 0.1.0"}]
end
Usage
To use Authenticator
, you’ll need to define the following functions:
tokenize(resource)
- Serialize the user into a “token” that can be stored in the session.authenticate(resource)
- Given a “token”, locate the user.fallback(conn, reason)
- Handle authentication errors.
Here’s an example implementation of an authenticator:
# lib/my_app_web/authenticator.ex
defmodule MyAppWeb.Authenticator do
use Authenticator
import Phoenix.Controller
import MyAppWeb.Router.Helpers
alias MyApp.Repo
alias MyApp.Accounts.User
@impl true
def tokenize(user) do
{:ok, to_string(user.id)}
end
@impl true
def authenticate(user_id) do
case Repo.get(User, user_id) do
nil ->
{:error, :not_found}
user ->
{:ok, user}
end
end
@impl true
def fallback(conn, :not_found) do
conn |> redirect(to: login_path(conn)) |> halt()
end
def fallback(conn, :not_authenticated) do
conn
|> put_flash(:error, "You need to sign in to continue.")
|> redirect(to: login_path(conn))
|> halt()
end
def fallback(conn, :not_unauthenticated) do
conn
|> put_flash(:error, "You are already signed in.")
|> redirect(to: root_path(conn))
|> halt()
end
end
Plugs
All of the plugs provided by Authenticator
expect your app’s authenticator as an argument.
pipeline :browser do
# snip...
plug Authenticator.Session, with: MyAppWeb.Authenticator
end
pipeline :authenticated do
plug Authenticator.Authenticated, with: MyAppWeb.Authenticator
end
scope "/", MyAppWeb do
pipe_through([:browser, :authenticated])
# declare protected routes here
end
Usage with Authority
Authenticator
supports Authority
and Authority.Ecto
out of the box.
Here’s an example authenticator that takes advantage of Autenticator.Authority
:
defmodule MyAppWeb.Authenticator do
use Authenticator
use Authenticator.Authority,
token_schema: Accounts.Token,
tokenization: Accounts,
authentication: Accounts
@impl true
def fallback(conn, _reason) do
conn
|> Plug.Conn.redirect(to: "/login")
|> Plug.Conn.halt()
end
end
Note: In the above example, we’re serializing the user into a token. If you’re using
Authority.Ecto
, tokens are stored in the database. The benefit of using a token (as opposed to the user’s ID), is that we can revoke specific sessions by deleting tokens from the database.