pow-auth / pow_assent

Multi-provider authentication for your Pow enabled app
https://powauth.com
MIT License
321 stars 50 forks source link

How to restrict registration based on email domain #170

Open danschultzer opened 4 years ago

danschultzer commented 4 years ago

Posted on slack:

Hello,

I am would like to validate user email while using pow assent to only accept user with a specific email address. My first attempt was to use this custom changeset (following the doc)

  def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do
    user_or_changeset
    |> cast(attrs, [:name, :preferred_username, :picture])
    |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs)
    |> validate_format(:email, ~r/@organization.com$/)
    |> retrieve_name
  end

it kind of work because the user is not directly added to the User table, but instead the user is redirected to “/:provider/add-user-id” from there, a user can just change the email address to use whatever he wants to and still be successfuly registered I struggle a lot to find other way to properly prevent a user to login if the email is not valid (edited)

danschultzer commented 4 years ago

The issue is here: https://github.com/pow-auth/pow_assent/blob/v0.4.7/lib/pow_assent/ecto/user_identities/context.ex#L213

When there's an error on email then it triggers the {:error, {:invalid_user_id_field, changeset}} error which will redirect to the add-user-id form. It can be solved by setting the error on a different key:

  def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do
    user_or_changeset
    |> cast(attrs, [:name, :preferred_username, :picture])
    |> pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs)
    |> maybe_add_email_domain_error()
    |> retrieve_name
  end

  defp maybe_add_email_domain_error(changeset) do
    changeset
    |> Ecto.Changeset.get_field(:email)
    |> String.ends_with?("@organization.com")
    |> case do
      true  -> changeset
      false -> Ecto.Changeset.add_error(changeset, :email_domain, "not valid")
    end
  end

However, I think that the current way email errors are handled is not very flexible. I will see how I can refactor the current logic in PowAssent to make this more flexible and so devs can more easily handle these scenarios.

formido commented 3 years ago

Thanks for the code in this issue, I needed this.