Comeonin v5.1.1 Comeonin behaviour View Source

Defines a behaviour for higher-level password hashing functions.

Link to this section Summary

Callbacks

Hashes a password and returns the password hash in a map, with the password set to nil

Checks the password by comparing its hash with the password hash found in a user struct, or map

Runs the password hash function, but always returns false

Link to this section Types

Link to this type

password() View Source
password() :: binary()

Link to this type

user_struct() View Source
user_struct() :: map() | nil

Link to this section Callbacks

Link to this callback

add_hash(password, opts) View Source
add_hash(password(), opts()) :: map()

Hashes a password and returns the password hash in a map, with the password set to nil.

In the default implementation, the key for the password hash is :password_hash. A different key can be used by using the hash_key option.

Example with Ecto

The put_pass_hash function below is an example of how you can use add_hash to add the password hash to the Ecto changeset.

defp put_pass_hash(%Ecto.Changeset{valid?: true, changes:
    %{password: password}} = changeset) do
  change(changeset, add_hash(password))
end

defp put_pass_hash(changeset), do: changeset

This function will return a changeset with %{password_hash: password_hash, password: nil} added to the changes map.

Link to this callback

check_pass(user_struct, password, opts) View Source
check_pass(user_struct(), password(), opts()) ::
  {:ok, map()} | {:error, String.t()}

Checks the password by comparing its hash with the password hash found in a user struct, or map.

The first argument to check_pass should be a user struct, a regular map, or nil.

In the default implementation, if the input to the first argument, the user struct, is nil, then the no_user_verify function is run, so as to prevent user enumeration. This can be disabled by setting the hide_user option to false.

Example

The following is an example of calling this function with no options:

def verify_user(%{"password" => password} = params) do

params
|> Accounts.get_by()
|> check_pass(password)

end

The Accounts.get_by function in this example takes the user parameters (for example, email and password) as input and returns a user struct or nil.

Link to this callback

no_user_verify(opts) View Source
no_user_verify(opts()) :: false

Runs the password hash function, but always returns false.

This function is intended to make it more difficult for any potential attacker to find valid usernames by using timing attacks. This function is only useful if it is used as part of a policy of hiding usernames.

Hiding usernames

In addition to keeping passwords secret, hiding the precise username can help make online attacks more difficult. An attacker would then have to guess a username / password combination, rather than just a password, to gain access.

This does not mean that the username should be kept completely secret. Adding a short numerical suffix to a user's name, for example, would be sufficient to increase the attacker's work considerably.

If you are implementing a policy of hiding usernames, it is important to make sure that the username is not revealed by any other part of your application.