I can't redirect to code entry page with magic_auth

I want it to be possible to sign up from different places than just the auth/log-in route.

And my problem is:

When i call an event “send_me_updates” i get redirected to desired url and then “/auth/password” even though when I print out the url with IO.inspect and input it manually into the address bar it works.

Code:

// project_live.ex
  def handle_event("send_me_updates", %{"email" => email}, socket) do
    if Repo.get_by(User, email: email) do
      {:noreply, socket}
    else
      MagicAuth.create_one_time_password(%{"email" => email})
      |> case do
        {:ok, _, _} ->
          IO.inspect "/auth/password?email=#{URI.encode_www_form(email)}", label: "REDIRLINK"
          {:noreply,
           push_navigate(socket, to: ~p"/auth/password?email=#{URI.encode_www_form(email)}")}

        {:error, changeset} ->
          {:noreply, socket}
      end
    end
  end
// magic_auth.ex
// This code probably isn't relevant but that's the only thing i changed within magic_auth.ex
  @impl true
  def one_time_password_requested(%{code: code, email: email}, retries \\ 10) do
    if Repo.exists?(from u in User, where: u.email == ^email) do
      send_access_code_email(code, email)
    else
      adjectives = ["happy", "clever", "swift", "bright", "gentle", "kind", "calm", "wise"]
      animals = ["panda", "koala", "tiger", "dolphin", "eagle", "rabbit", "fox", "owl"]

      # Generate a base handle using a random adjective and animal
      base_handle = "#{Enum.random(adjectives)}_#{Enum.random(animals)}"

      random_number = :rand.uniform(999_999)

      unique_handle = "#{base_handle}_#{random_number}"
      unique_name = "#{String.capitalize(base_handle)} #{random_number}"

      # Ensure the handle is unique in the database
      case Repo.get_by(User, handle: unique_handle) do
        nil ->
          %User{}
          |> User.registration_changeset(%{name: unique_name, handle: unique_handle, email: email})
          |> Repo.insert()
          |> case do
            {:ok, user} -> send_access_code_email(code, email)
            {:error, _changeset} -> {:error, :user_creation_failed}
          end

        _existing_user ->
          if retries > 0 do
            # retry with a new random number
            one_time_password_requested(%{code: code, email: email}, retries - 1)
          else
            {:error, :max_retries_reached}
          end
      end
    end
  end

  defp send_access_code_email(code, email) do
    Swoosh.Email.new()
    |> Swoosh.Email.to(email)
    |> Swoosh.Email.from({"PREREL", "hello@prerel.com"})
    |> Swoosh.Email.subject("Access code for PREREL")
    |> Swoosh.Email.text_body(text_email_body(code))
    |> Swoosh.Email.html_body(html_email_body(code))
    |> Prerel.Mailer.deliver()
  end
  @impl true
  def log_in_requested(%{email: email}) do
    # updates last_login_at
    case Repo.get_by(User, email: email) do
      nil ->
        :deny

      user ->
        user
        |> Ecto.Changeset.change(
          last_login_at: NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
        )
        |> Repo.update()

        :allow
    end
  end

I don’t know anything about this library but I think you are encoding the param twice which causes it to fail validation and redirect.

The ~p sigil should already be encoding the interpolated param for you, so you don’t need that.

Note that the version you’re inspect()ing is not using ~p, which is why it’s different.

1 Like

oooooh, I didn’t know that using ~p already encodes the param, thanks!