Skip to content

polyfox/passport

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Passport

An opionated Authentication Framework for Elixir Phoenix.

Installation

If available in Hex, the package can be installed by adding passport to your list of dependencies in mix.exs:

def deps do
  [
    {:passport, "~> 0.3.0"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/passport.

Modules

  • Activatable activatable
  • Authenticatable authenticatable
  • Confirmable confirmable
  • Lockable lockable
  • Recoverable recoverable
  • Rememberable rememberable - not implemented
  • Trackable trackable
  • TwoFactorAuth two_factor_auth

Schema

Activatable Fields

Name Type Description
active boolean Is the entity active, field will be available if activatable_is_flag is true for the entityy's config
activated_at utc_datetime When was the entity activated, field will be present if activatable_if_flag is false

Authenticatable Fields

Name Type Description
old_password string virtual
password string virtual
password_confirmation string virtual
password_changed boolean virtual Was the password changed in the latest update?
password_hash string The stored password hash.

Confirmable Fields

Name Type Description
confirmation_token string A randomly generated token used to confirm the entity.
confirmed_at utc_datetime When was the entity confirmed?
confirmation_sent_at utc_datetime When was the confirmation message sent to the entity's email?

Lockable Fields

Name Type Description
failed_attempts integer How many times has the entity failed to login?
locked_at utc_datetime When was the entity locked due to login failures?
lock_changed boolean virtual Was the locked_at changed during the last update?

Recoverable Fields

Name Type Description
reset_password_token string A randomly generated token used to reset the user's password
reset_password_sent_at utc_datetime When was the password reset sent?

Rememberable Fields

Name Type Description
remember_created_at utc_datetime

Trackable Fields

Name Type Description
sign_in_count integer How many times has the entity successfully authenticated and created a new session.
current_sign_in_at utc_datetime When did the entity successfully authenticate?
current_sign_in_ip integer Current IP the entity authenticated from.
last_sign_in_at utc_datetime When the entity previously authenticated?
last_sign_in_ip integer Previous IP the entity authenticated from.

TwoFactorAuth Fields

Name Type Description
tfa_otp_secret_key string The key used for generating One Time Passcodes.
tfa_enabled boolean Is Two Factor Auth enabled for the entity?
tfa_attempts_count integer How many failed two factor auth attempts have happened since last successful one?
tfa_recovery_tokens array<string> A list of tokens used in place of an otp.

Default Routes

Authenticatable Routes

Provided by Passport.SessionController

Logout

  • DELETE /login
  • POST /logout

Login

  • POST /login

Confirmable Routes

Provided by Passport.ConfirmationController

Request Email Confirmation

  • POST /confirm/email

Retrieve Email Confirmation Details

  • GET /confirm/email/:token

Confirm Email

  • POST /confirm/email/:token

Cancel Email Confirmation

  • DELETE /confirm/email/:token

Recoverable Routes

Provided by Passport.PasswordController

Request Password Reset

  • POST /password

Complete Password Reset

  • POST /password/:token
  • PATCH /password/:token
  • PUT /password/:token

Cancel Password Reset

  • DELETE /password/:token

TwoFactorAuth Routes

Provided by Passport.TwoFactorController

Reset TFA Secret

  • POST /reset/tfa

Confirm TFA

  • POST /confirm/tfa

Usage

Config

Passport has a handful of config options that are required for the library to work correctly:

config :passport,
  # the phoenix error view to use when rendering the api errors
  error_view: Passport.Support.Web.ErrorView,
  # a context module used for creating, retrieiving and managing sessions
  sessions_client: Passport.Support.Sessions,
  # the writable ecto repository, can be the same as the replica
  primary_repo: Passport.Support.Repo,
  # the readable ecto repository, can be the same as the primary
  replica_repo: Passport.Support.Repo

Schema

#$ mix passport.init ModelName table_name
$ mix passport.init User users

Models

defmodule MyApp.User do
  use Ecto.Schema

  schema "users" do
    timestamps()

    field :email, :string

    Passport.schema_fields()
  end
end

By default Passport includes all it's available modules, individual modules can chosen by providing a list to the schema_fields call

Passport.schema_fields([:authenticatable, :lockable, :two_factor_auth])

Controllers

defmodule MyApp.Web.ConfirmationController do
  use MyApp.Web, :controller
  use Passport.ConfirmationController, confirmable_model: MyApp.User
end
defmodule MyApp.Web.PasswordController do
  use MyApp.Web, :controller
  use Passport.PasswordController, recoverable_model: MyApp.User

  @impl true
  def request_reset_password(params) do
    email = params["email"]
    case Passport.Repo.replica().get_by!(Passport.Support.User, email: email) do
      nil ->
        {:error, :not_found}
      entity ->
        Passport.prepare_reset_password(entity)
    end
  end
end
defmodule MyApp.Web.SessionController do
  use MyApp.Web, :controller
  use Passport.SessionController
end
defmodule MyApp.Web.TwoFactorAuthController do
  use MyApp.Web, :controller
  use Passport.TwoFactorAuthController
end

Contexts

Passport only requires a single context to be implemented, it's Sessions context, there it will handle retrieving sessions and their entities as well as checking authentication details.

The module must be configered via config :passport, sessions_client: ModuleName

defmodule Passport.Support.Sessions do
  # imports extract_password/1 and extract_auth_code/1
  use Passport.Sessions

  @impl true
  def find_entity_by_identity(identity) do
    Passport.Support.Users.find_user_by_email(identity)
  end

  @impl true
  def check_authentication(entity, params) do
    Passport.check_authenticatable(entity, extract_password(params))
  end

  @impl true
  def create_session(entity, _params) do
    # for simplicity sake use the entity's id as the token
    {:ok, {entity.id, entity}}
  end

  @impl true
  def get_session(token) do
    {:ok, [user: Passport.Support.Users.get_user(token), token: token]}
  end

  @impl true
  def destroy_session(%{user: user} = assigns) do
    # nothing to do here, we don't exactly have an api keys table yet
    {:ok, user}
  end
end

Issuing a Password Change

# for immediately changing it
{:ok, entity} =
  Passport.change_password(entity, %{
    old_password: "my_old_password",
    password: "new_password",
    password_confirmation: "new_password"
  })
# as apart of a changeset
changeset =
  Passport.changeset(entity, %{
    old_password: "my_old_password",
    password: "new_password",
    password_confirmation: "new_password"
  }, :password_change)