Packages

Authorization library for Elixir applications

Current section

Files

Jump to
auth_z lib authorization_plug_mixin.ex
Raw

lib/authorization_plug_mixin.ex

defmodule AuthZ.AuthorizationPlugMixin do
@moduledoc ~S"""
Allows to create a plug enforcing authorization for protected routes.
A user-defined module must `use` this module, making the user module a plug, and
implement the `handle_authorization/3` and `handle_authentication_error/2`
behaviours. The `handle_authorization/3` and `handle_authentication_error/2`
callbacks receive a `Plug.Conn` struct and an atom identifying the set of routes
that require authorization, and must return a `Plug.Conn` struct;
`handle_authorization/3` additionally receives the logged in user.
Example:
```
defmodule MyAppWeb.Plugs.EnsureAuthorized do
use AuthZ.AuthorizationPlugMixin
import Plug.Conn
import Phoenix.Controller
alias MyApp.Accounts.User
def handle_authentication_error(conn, :admin_routes),
do: conn |> put_status(401) |> text("unauthenticated") |> halt()
def handle_authorization(conn, %User{type: "admin"}, :admin_routes),
do: conn
def handle_authorization(conn, _, _),
do: conn |> put_status(403) |> text("unauthorized") |> halt()
end
```
`EnsureAuthorized` is now a plug which can be used in the router:
```
pipeline :ensure_admin_routes_authorized do
plug MyAppWeb.Plugs.EnsureAuthorized,
resource: :admin_routes
end
scope "/admin", MyAppWeb, as: :admin do
pipe_through [:browser, :ensure_admin_routes_authorized]
# code
end
```
"""
@callback handle_authorization(Plug.Conn.t(), term, atom) :: Plug.Conn.t()
@callback handle_authentication_error(Plug.Conn.t(), atom) :: Plug.Conn.t()
defmacro __using__(_args) do
this_module = __MODULE__
quote do
@behaviour unquote(this_module)
def init(opts) do
Keyword.fetch!(opts, :resource)
opts
end
def call(conn, opts) do
current_user = Map.get(conn.assigns, :current_user)
authorize(conn, current_user, opts)
end
defp authorize(conn, nil, opts) do
__MODULE__.handle_authentication_error(conn, Keyword.fetch!(opts, :resource))
end
defp authorize(conn, current_user, opts) do
__MODULE__.handle_authorization(conn, current_user, Keyword.fetch!(opts, :resource))
end
end
end
end