Packages
phauxth
1.2.6
2.5.1
retired
2.5.0
2.4.0
2.3.2
2.3.1
2.3.0
2.2.0
2.1.1
2.1.0
2.0.1
2.0.0
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
2.0.0-beta.1
2.0.0-beta.0
2.0.0-alpha.5
2.0.0-alpha.4
retired
2.0.0-alpha.3
retired
2.0.0-alpha.2
retired
2.0.0-alpha.1
retired
2.0.0-alpha.0
retired
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.1
1.2.0
1.1.3
1.1.2
1.1.1
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
0.17.1
0.17.0
0.16.0
0.15.1
0.15.0
0.14.0
0.13.0-rc.1
0.13.0-rc.0
0.12.1-rc.1
0.12.1-rc.0
0.12.0-rc
0.11.0
0.10.3
0.10.2
0.10.0
0.9.0
0.8.2
0.8.1
0.8.0
Authentication library for Phoenix, and other Plug-based, web applications
Current section
Files
Jump to
Current section
Files
lib/phauxth/authenticate/base.ex
defmodule Phauxth.Authenticate.Base do
@moduledoc """
Base module for authentication.
This is used by Phauxth.Authenticate and Phauxth.Remember.
It can also be used to produce a custom authentication module,
as outlined below.
## Custom authentication modules
The next sections give examples of extending this module to create
custom authentication modules.
### Graphql authentication
The following module is another example of how this Base module can
be extended, this time to provide authentication for absinthe-elixir:
defmodule AbsintheAuthenticate do
use Phauxth.Authenticate.Base
def set_user(user, conn) do
put_private(conn, :absinthe, %{token: %{current_user: user}})
end
end
And in the `router.ex` file, call this plug in the pipeline you
want to authenticate (setting the method to :token).
pipeline :api do
plug :accepts, ["json"]
plug AbsintheAuthenticate, method: :token
end
### Authentication for use with Phoenix channels
In this example, after adding the user struct to the current_user value,
a token is added (for use with Phoenix channels).
defmodule MyAppWeb.Authenticate do
use Phauxth.Authenticate.Base
def set_user(nil, conn), do: assign(conn, :current_user, nil)
def set_user(user, conn) do
token = Phauxth.Token.sign(conn, %{"user_id" => user.email})
assign(conn, :current_user, user)
|> assign(:user_token, token)
end
end
MyAppWeb.Authenticate is called in the same way as Phauxth.Authenticate.
You can then use Phauxth.Token.verify, in the `user_socket.ex` file, to
verify the token.
### Custom session / token implementations
This module uses Plug sessions or Phauxth tokens (based on Phoenix.Token)
by default. To use custom sessions or tokens, you need to create your
own custom Authenticate module and override the `check_session` or
`check_token` function.
"""
@doc false
defmacro __using__(_) do
quote do
import Plug.Conn
alias Phauxth.{Config, Log, Token, Utils}
@behaviour Plug
@doc false
def init(opts) do
{
{
Keyword.get(opts, :method, :session),
Keyword.get(opts, :max_age, 4 * 60 * 60),
Keyword.get(opts, :user_context, Phauxth.Config.user_context()),
opts
},
Keyword.get(opts, :log_meta, [])
}
end
@doc false
def call(conn, {opts, log_meta}) do
get_user(conn, opts) |> report(log_meta) |> set_user(conn)
end
@doc """
Get the user based on the session id or token id.
This function also calls the database to get user information.
"""
def get_user(conn, {:session, max_age, user_context, _}) do
with {session_id, user_id} <- check_session(conn),
%{sessions: sessions} = user <- user_context.get(user_id),
timestamp when is_integer(timestamp) <- sessions[session_id],
do:
(timestamp + max_age > System.system_time(:second) and user) ||
{:error, "session expired"}
end
def get_user(%Plug.Conn{req_headers: headers} = conn, {:token, max_age, user_context, opts}) do
with {_, token} <- List.keyfind(headers, "authorization", 0),
{:ok, user_id} <- check_token(conn, token, max_age, opts),
do: user_context.get(user_id)
end
@doc """
Check the session for the current user.
"""
def check_session(conn) do
with <<session_id::binary-size(17), user_id::binary>> <-
get_session(conn, :phauxth_session_id),
do: {session_id, user_id}
end
@doc """
Check the token for the current user.
"""
def check_token(conn, token, max_age, opts) do
Token.verify(conn, token, max_age, opts)
end
@doc """
Log the result of the authentication and return the user struct or nil.
"""
def report(%{} = user, meta) do
Log.info(%Log{user: user.id, message: "user authenticated", meta: meta})
Map.drop(user, Config.drop_user_keys())
end
def report({:error, message}, meta) do
Log.info(%Log{message: message, meta: meta}) && nil
end
def report(nil, meta) do
Log.info(%Log{message: "anonymous user", meta: meta}) && nil
end
@doc """
Set the `current_user` variable.
"""
def set_user(user, conn) do
assign(conn, :current_user, user)
end
@doc """
Checks to see if the session is fresh - newly logged in.
"""
def fresh_session?(conn) do
get_session(conn, :phauxth_session_id) |> check_session_id
end
defp check_session_id("F" <> _), do: true
defp check_session_id(_), do: false
defoverridable init: 1,
call: 2,
get_user: 2,
check_session: 1,
check_token: 4,
report: 2,
set_user: 2
end
end
end