Home

Awesome

[ProjectTalk] (http://www.projecttalk.io/boards/manukall%2Fphoenix_token_auth?utm_campaign=gh-badge&utm_medium=badge&utm_source=github)

PhoenixTokenAuth is not really maintained. I do not recommend starting a new project with it.

I'm not actively using this project at the moment. I also implmemented most of it when I just started with Elixir, so the code is not exactly great. If you want to use it, be prepared to fork the project and invest some work.

PhoenixTokenAuth

Adds token authentication to Phoenix apps using Ecto.

An example app is available at https://github.com/manukall/phoenix_token_auth_react.

Setup

You need to have a user model with at least the following schema and callback:

defmodule MyApp.User do
  use Ecto.Model

  schema "users" do
    field  :email,                       :string     # or :username
    field  :hashed_password,             :string
    field  :hashed_confirmation_token,   :string
    field  :confirmed_at,                Ecto.DateTime
    field  :hashed_password_reset_token, :string
    field  :unconfirmed_email,           :string
    field  :authentication_tokens,       {:array, :string}, default: []
  end

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

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

end

Make sure that you have uniqueness constraints on the email or username columns.

Then add PhoenixTokenAuth to your Phoenix router:

defmodule MyApp.Router do
  use Phoenix.Router
  require PhoenixTokenAuth

  pipeline :authenticated do
    plug PhoenixTokenAuth.Plug
  end

  scope "/api" do
    pipe_through :api

    PhoenixTokenAuth.mount
  end

  scope "/api" do
    pipe_through :authenticated
    pipe_through :api

    resources "/messages", MessagesController
  end
end

This generates routes for sign-up and login and protects the messages resources from unauthenticated access.

The generated routes are:

methodpathdescription
POST/api/userssign up
POST/api/users/:id/confirmconfirm account
POST/api/sessionlogin, will return a token as JSON
DELETE/api/sessionlogout, invalidated the users current authentication token
POST/api/password_resetsrequest a reset-password-email
POST/api/password_resets/resetreset a password
GET/api/accountget information about the current user. at the moment this includes only the email address
PUT/api/accountupdate the current users email or password

If you want to customize the routes, instead of

  scope "/api" do
    pipe_through :api

    PhoenixTokenAuth.mount
  end

add

  scope "/api" do
    pipe_through :api

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

And customize, change names/pipeline of the routes.

Inside the controller, the authenticated user is accessible inside the connections assigns:

def index(conn, _params) do
  user_id = conn.assigns.authenticated_user.id
  ...
end

Now add configuration:

# config/config.exs
config :phoenix_token_auth,
  user_model: Myapp.User,                                                              # ecto model used for authentication
  repo: Myapp.Repo,                                                                    # ecto repo
  crypto_provider: Comeonin.Bcrypt,                                                    # crypto provider for hashing passwords/tokens. see http://hexdocs.pm/comeonin/
  token_validity_in_minutes: 7 * 24 * 60,                                              # minutes from login until a token expires
  email_sender: "myapp@example.com",                                                   # sender address of emails sent by the app
  emailing_module: MyApp.EmailConstructor,                                             # module implementing the `PhoenixTokenAuth.MailingBehaviour` for generating emails
  mailgun_domain: "example.com",                                                       # domain of your mailgun account
  mailgun_key: "secret",                                                               # secret key of your mailgun account
  user_model_validator: {MyApp.Model, :user_validator}                                 # function receiving and returning the changeset for a user on registration and when updating the account. This is the place to run custom validations.

The secret key for signing tokens must be provided for Joken to work. You must also configure the JSON encoder for Joken to use. For using the Poison Encode function, we provide the PhoenixTokenAuth.PoisonHelper. The secret_key should be set per environment and should not be committed to the repository.

# config/config.exs
config :joken,
  json_module: PhoenixTokenAuth.PoisonHelper,
  algorithm: :HS256 # Optional. defaults to :HS256
# config/[dev|test|prod].exs
config :joken,
  # Environment specific secret key for signing tokens.
  # This should be a very long random string.
  secret_key: "very secret test key",

Usage

Signing up / Registering a new user

Signing up / Registering a new user with username

Confirming a user

Logging in

Logging in with username

Requesting a protected resource

Logging out

Resetting password

Change the current user's password

Change the current user's email address

TODO: