Packages

Elixir authentication and authorization

Current section

Files

Jump to
auth_shield lib authx_ex credentials schemas password_schema.ex
Raw

lib/authx_ex/credentials/schemas/password_schema.ex

defmodule AuthShield.Credentials.Schemas.Password do
@moduledoc """
Password schema model.
We do not save users password, only the encripted hash that will
be used to authenticate.
To see more about how we hash the password check `Argon2`.
"""
use Ecto.Schema
import Ecto.Changeset
alias AuthShield.Resources.Schemas.User
@typedoc """
Abstract password module type.
"""
@type t :: %__MODULE__{
id: binary(),
user: User.t(),
password_hash: String.t(),
inserted_at: NaiveDateTime.t(),
updated_at: NaiveDateTime.t()
}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
@required_fields [:password, :user_id]
schema "password_credentials" do
field(:password, :string, virtual: true)
field(:password_hash, :string)
belongs_to(:user, User)
timestamps()
end
@doc """
Generates an `Ecto.Changeset` struct with the changes.
It defines validations and also generates the password hash if
necessary.
"""
@spec changeset(model :: t(), params :: map()) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = model, params) when is_map(params) do
model
|> cast(params, @required_fields)
|> validate_required(@required_fields)
|> validate_length(:password, min: 6, max: 150)
|> unique_constraint(:user_id)
|> put_pass_hash()
end
@doc """
Generates an `Ecto.Changeset` to be used on assoc with the user.
It defines validations and also generates the password hash if
necessary.
"""
@spec changeset_assoc(model :: t(), params :: map()) :: Ecto.Changeset.t()
def changeset_assoc(%__MODULE__{} = model, params) when is_map(params) do
model
|> cast(params, [:password])
|> validate_required([:password])
|> validate_length(:password, min: 6, max: 150)
|> unique_constraint(:user_id)
|> put_pass_hash()
end
defp put_pass_hash(%{valid?: true, changes: %{password: pwd}} = changeset) do
# Append the password hash to the changeset
# We use `Argon2` to hash and verify the password
#
# See more in https://hexdocs.pm/argon2_elixir/Argon2.html
change(changeset, %{password_hash: Argon2.hash_pwd_salt(pwd), password: nil})
end
defp put_pass_hash(changeset), do: changeset
end