Packages

Integration with the Auth API from Supabase services. Provide authentication with MFA, password and magic link.

Current section

Files

Jump to
supabase_auth lib supabase auth schemas generate_link.ex
Raw

lib/supabase/auth/schemas/generate_link.ex

defmodule Supabase.Auth.Schemas.GenerateLink do
@moduledoc false
import Ecto.Changeset
@types ~w[signup invite magicLink recovery email_change_current email_change_new]a
@options_types %{data: :map, redirect_to: :string}
@base_types %{
email: :string,
type: Ecto.ParameterizedType.init(Ecto.Enum, values: @types)
}
@properties_types %{
action_link: :string,
email_otp: :string,
hashed_token: :string,
redirect_to: :string,
verification_type: Ecto.ParameterizedType.init(Ecto.Enum, values: @types)
}
def properties(attrs) do
{%{}, @properties_types}
|> cast(attrs, Map.keys(@properties_types))
|> validate_required(Map.keys(@properties_types))
|> apply_action(:parse)
end
def parse(attrs) do
Enum.reduce_while(
[
&sign_up_params/1,
&invite_or_magic_link_params/1,
&recovery_params/1,
&email_change_params/1
],
nil,
fn schema, _ ->
case result = schema.(attrs) do
{:ok, _} -> {:halt, result}
{:error, _} -> {:cont, result}
end
end
)
end
def sign_up_params(attrs) do
types = with_options(%{password: :string})
{%{}, types}
|> cast(attrs, Map.keys(types))
|> validate_required([:email, :password, :type])
|> validate_redirect_to()
|> validate_change(:type, fn _, type ->
check_type(type, :signup)
end)
|> apply_action(:parse)
end
def invite_or_magic_link_params(attrs) do
types = with_options()
{%{}, types}
|> cast(attrs, Map.keys(types) -- [:data])
|> validate_required([:email, :type])
|> validate_redirect_to()
|> validate_inclusion(:type, ~w[invite magicLink]a)
|> apply_action(:parse)
end
def recovery_params(attrs) do
types = with_options()
{%{}, types}
|> cast(attrs, Map.keys(types) -- [:data])
|> validate_redirect_to()
|> validate_change(:type, fn _, type ->
check_type(type, :recovery)
end)
|> validate_required([:email, :type])
|> apply_action(:parse)
end
def email_change_params(attrs) do
types = with_options()
{%{}, types}
|> cast(attrs, Map.keys(types) -- [:data])
|> validate_required([:email, :type])
|> validate_redirect_to()
|> validate_inclusion(:type, ~w[email_change_current email_change_new]a)
|> apply_action(:parse)
end
defp with_options(types \\ %{}) do
@base_types
|> Map.merge(types)
|> Map.merge(@options_types)
end
defp check_type(current, desired) do
if current == desired do
[]
else
[type: "need to be #{desired} for this schema"]
end
end
defp validate_redirect_to(%{valid?: false} = changeset), do: changeset
defp validate_redirect_to(changeset) do
if redirect_to = get_change(changeset, :redirect_to) do
case URI.new(redirect_to) do
{:ok, uri} -> put_change(changeset, :redirect_to, URI.to_string(uri))
{:error, error} -> add_error(changeset, :redirect_to, error)
end
else
changeset
end
end
end