README.md

# Sentinel
[![Build
Status](https://travis-ci.org/britton-jb/sentinel.svg?branch=master)](https://travis-ci.org/britton-jb/sentinel)

Things I wish [Guardian](https://github.com/ueberauth/guardian) included
out of the box. Routing, confirmation emails, password reset emails.
It's just a thin wrapper on Guardian buteverybody shouldn't have to repeat
this themselves when they build stuff.

Suggestions? See the `Contributing/Want something new?` section.

## Installation
Here's how to add it to your phoenix project, and things you need to
setup:

```
# mix.exs
{:sentinel, "~> 1.0.0"},

# If you'd like to database back your tokens, and prevent replayability
{:guardian_db, "~> 0.7.0"},
```

### The User Model
Your user model must have at least the following fields, and the
`permissions/1` function must be defined, in order to encode permissions
into your token, currently even if the function is empty, and you don't
plan on using [Guardian
permissions](https://github.com/ueberauth/guardian/#permissions).

```elixir
defmodule MyApp.User do
  use Ecto.Schema

  schema "users" do
    field  :email,                       :string     # or :username
    field  :role,                        :string
    field  :hashed_password,             :string
    field  :hashed_confirmation_token,   :string
    field  :confirmed_at,                Ecto.DateTime
    field  :hashed_password_reset_token, :string
    field  :unconfirmed_email,           :string
  end

  @required_fields ~w(email)
  @optional_fields ~w()

  def changeset(struct, params \\ :empty) do
    struct
    |> cast(params, @required_fields, @optional_fields)
  end

  def permissions(role) do
  end
end
```

### Configure Guardian
Example config:

```
config :guardian, Guardian,
  allowed_algos: ["HS512"], # optional
  verify_module: Guardian.JWT,  # optional
  issuer: "MyApp",
  ttl: { 30, :days },
  verify_issuer: true, # optional
  secret_key: "guardian_sekret",
  serializer: Sentinel.GuardianSerializer,
  hooks: GuardianDb
```

[More info](https://github.com/ueberauth/guardian#installation)

### Configure GuardianDb
```
config :guardian_db, GuardianDb,
  repo: MyApp.Repo
```

The database backing for your tokens:

```elixir
defmodule MyApp.Repo.Migrations.GuardianDb do
  use Ecto.Migration

  def up do
    create table(:guardian_tokens, primary_key: false) do
      add :jti, :string, primary_key: true
      add :typ, :string
      add :aud, :string
      add :iss, :string
      add :sub, :string
      add :exp, :bigint
      add :jwt, :text
      add :claims, :map
      timestamps
    end
  end

  def down do
    drop table(:guardian_tokens)
  end
end
```

[More info](https://github.com/hassox/guardian_db)

### Configure Sentinel
```
config :sentinel,
  app_name: "Test App",
  user_model: MyApp.User,
  email_sender: "test@example.com",
  crypto_provider: Comeonin.Bcrypt,
  auth_handler: Sentinel.AuthHandler, #optional
  repo: MyApp.Repo,
  confirmable: :required, # possible options {:false, :required, :optional}, optional config, defaulting to :optional
  invitable: :required, # possible options {:false, :true}, optional config, defaulting to false
  endpoint: MyApp.Endpoint,
  router: MyApp.Router,
  user_view: MyApp.UserModel.View,
  environment: :development
```

See `config/test.exs` for more current examples of configuring Sentinel

### Configure Bamboo
[More info](https://github.com/thoughtbot/bamboo/)

### Routes
Add the following to your routes file to add default routes, complete
with protection

```elixir
defmodule MyApp.Router do
  use MyApp.Web, :router
  require Sentinel

  scope "/" do
    pipe_through :browser

    Sentinel.mount_html
  end

  scope "/api" do
    pipe_through :api

    Sentinel.mount_api
  end
end
```

The generated routes are shown in `/lib/sentinel.ex`:

method | path | description
-------|------|------------
POST | /api/users | register
POST | /api/users/:id/confirm | confirm account
POST | /api/users/:id/invited | set password on invited account
POST | /api/sessions | login, will return a token as JSON
DELETE |  /api/sessions | logout, invalidated the users current authentication token
POST | /api/password_resets | request a reset-password-email
POST | /api/password_resets/reset | reset a password
GET  | /api/account               | get information about the current user. at the moment this includes only the email address
PUT  | /api/account               | update the current users email or password

You may run into an issue here if you set the scope to `scope "/api",
MyApp.Router do`. Something to be aware of.

## Overriding the Defaults

### Confirmable
By default users are not required to confirm their account to login. If
you'd like to require confirmation set the `confirmable` configuration
field to `:required`. If you don't want confirmation emails sent, set
the field to `:false`. The default is `:optional`.

### Invitable
By default, users are required to have a password upon creation. If
you'd like to enable users to create accounts on behalf of other users
without a password you can set the `invitable` configuration field to
`true`. This will result in the user being sent an email with a link to
`GET users/:id/invited`, which you can complete by posting to the same
URL, with the following params:

json
```
{
  confirmation_token: confirmation_token_from_email_provided_as_url_param,
  password_reset_token: password_reset_token_from_email_provided_as_url_param,
  password: newly_defined_user_password
}
```

Note that the `invitable` module requires you to provide your own setup
your password form at `GET UserController :invited`. In the future when
Sentinel ships with views it's something I'd like to include. I would
gladly take PRs for some basic server rendered html forms.

### Custom Routes
If you want to customize the routes, or use your own controller
endpoints you can do that by overriding the individual routes shown
below:

```elixir
post  "users",                 Sentinel.Controllers.Users, :create
post  "users/:id/confirm",     Sentinel.Controllers.Users, :confirm
post  "users/:id/invited",     Sentinel.Controllers.Users, :invited
post  "sessions", Sentinel.Controllers.Sessions, :create
delete  "sessions", Sentinel.Controllers.Sessions, :delete
post  "password_resets", Sentinel.Controllers.PasswordResets, :create
post  "password_resets/reset", Sentinel.Controllers.PasswordResets, :reset
get   "account",               Sentinel.Controllers.Account, :show
put   "account",               Sentinel.Controllers.Account, :update
```

### Auth Error Handler
If you'd like to write your own custom authorization or authentication
handler change the `auth_handler` Sentinel configuration option
to the module name of your handler.

It must define two functions, `unauthorized/2`, and `unauthenticated/2`,
where the first parameter is the connection, and the second is
information about the session.

## Notes
1.0.0 attempted to utilize the semantic versioning tradition of
increasing the major version on breaking changes. There are many
breaking changes in this update.

## Contributing/Want something new?
Create an issue. Preferably with a PR. If you're super awesome
include tests.

As you recall from the license, this is provided as is. I don't make any
money on this, so I do support when I feel like it. That said, I want to
do my best to contribute to the Elixir/Phoenix community, so I'll do
what I can.

Having said that if you bother to put up a PR I'll take a look, and
either merge it, or let you know what needs to change before I do.
Having experienced sending in PRs and never hearing anything about
them, I know it sucks.

## TODO
- README DOCUMENT :sentinel, :send_emails, ecto 2 syntax changes,
  overriding Sentinel.EmailView and Sentinel.EmailLayoutView, other old
  stuff/general doc update, applying custom layouts via the router plug