README.md

# Doorman

Modules and functions to make authentication with Plug/Phoenix and Ecto easy
without tons of configuration or boxing users into rigid framework.

You can find more in-depth [documentation here](https://hexdocs.pm/doorman).

## Installation

Add doorman to your dependencies in `mix.exs`.

```elixir
def deps do
  [{:doorman, "~> 0.0.3"}]
end
```

Then add the configuration to `config/config.exs`.

```elixir
config :doorman,
  repo: MyApp.Repo,
  user_module: MyApp.User,
```

## Phoenix Quick Start

First generate a user model with a `password_digest` field.

```sh
$ mix ecto.gen.model User users email password_digest
```

Next, use `Doorman.Auth.Bcrypt` in your new `User` module and add a virtual
`password` field. `hash_password/1` is used in the changeset to hash our
password and put it into the changeset as `password_digest`.


```elixir
defmodule MyApp.User do
  use MyApp.Web, :model
  use Doorman.Auth.Bcrypt

  schema "users" do
    field :email, :string
    field :password_digest, :string
    field :password, :string, virtual: true

    timestamps
  end

  def create_changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:email, :oauth_token])
    |> hash_password
  end
end
```

Finally, we can add our plug so we can have access to `current_user` on
`conn.assigns`. A login strategy must to be passed in as an argument so Doorman
can find the current user.

```elixir
plug Doorman, Doorman.Login.Session
```

### Creating Users

To create a user we can use the `MyApp.create_changeset/2` function we defined.

```elixir
defmodule MyApp.UserController do
  alias MyApp.User

  def new(conn, _params) do
    changeset = User.create_changeset(%User{})
    conn |> render("new.html", changeset: changeset)
  end

  def create(conn, %{"user" => user_params}) do
    changeset = User.create_changeset(%User{}, user_params)

    case Repo.insert(changeset) do
      {:ok, user} ->
        conn |> redirect(to: "/")
      {:error, changeset} ->
        conn |> render("new.html", changeset: changeset)
    end
  end
end
```

### Logging in users

To accept logins we can use `Doorman.Login.Session.login/2`.

```elixir
defmodule MyApp.SessionController do
  import Doorman.Login.Session, only: [login: 2]

  def create(conn, %{"email" => email, "password" => "password"})
    if user = MyApp.Repo.get_by(MyApp.User, email: email) do
      if MyApp.User.authenticate(user, password) do
        conn
        |> login(user) # Sets :user_id on conn's session
        |> put_flash(:notice, "Successfully logged in")
        |> redirect(to: "/")
      else
        conn
        |> put_flash(:error, "Password was incorrect")
        |> render "new.html"
      end
    else
      conn
      |> put_flash(:error, "No account for provided email found")
      |> render "new.html"
    end
  end
end
```

### Requiring Authentication

To require a user to be authenticated the `Doorman.RequireLogin` plug can be
used. It requires a function to be passed to it in order to handle
unauthenticated requests.

```elixir
plug Doorman.RequireLogin, &redirect_to_login/1

defp redirect_to_login(conn) do
  conn |> redirect(to: session_path(conn, :new)) |> Plug.Conn.halt
end
```