mbski

mbski

Pow reset password - custom controller questions

Hi, for learning purposes I create API using Elixir/Phoenix. I’ve created whole custom authentication and after that I do the same using POW with custom controllers (just to learn how it works under the hood and have my boilerplates for next projects).

I stopped for a while doing custom controllers for Forgot password and reset password functions.

I read a lot of topics on forum but still i can’t pass through reset and update new password.

My function to forgot_password looks like that:

  @spec forgot_password(Conn.t(), map()) :: Conn.t()
  def forgot_password(conn, %{"user" => user_params}) do
    conn
    |> PowResetPassword.Plug.create_reset_token(user_params)
    |> case do
      {:ok, %{token: token, user: _user}, conn} ->
        #send email
        conn
        |> put_status(200)
        |> json(%{data: %{status: 200, message: "Email has been sent", token: token}})

      {:error, _changeset, conn} ->
        conn
        |> put_status(200)
        |> json(%{data: %{status: 200, message: "Email has been sent"}})
    end
  end

Its pretty straighforward. Always giving status 200 for security purposes, and token for passing it in POSTMAN during resetting password. I know that it should never go to production like that and Pow token is stored in cache. If You have some advices how to use Postman for authorization without passing tokens by hand in body I’d appreciate that (similar I have shown access tokens and renewal for register/login controllers)

For reset_password I wrote that function:

def reset_password(conn, %{"id" => token, "user" => user_params}) do

    with {:ok, conn} <- PowResetPassword.Plug.load_user_by_token(conn, token),
         {:ok, _user, conn}  <- PowResetPassword.Plug.update_user_password(conn, user_params) do
          conn
          |> put_status(:ok)
          |> json(%{status: "Password changed"})
    else
          {:error, changeset} ->
            {:error, changeset, conn}

          _ ->
            conn
            |> json(%{error: %{message: "Expired Token"}})
    end
end

The problem is like I found in docs and while testing, that update_user_password never returns an error when password and confirmation are not equal in this case (but in plug.ex its written that in should return {:error, changeset, conn}.
It returns “Password changed” and “Expired token”. Even if I put different passwords in body. Of course it doesnt change password then but I want to have two different errors if user makes mistake during writing password.

I found also on forum that function

  @spec reset_password(Conn.t(), map()) :: Conn.t()
  def reset_password(conn, %{"id" => token, "user" => user_params}) do
   conn
   |> PowResetPassword.Plug.load_user_by_token(token)
   |> case do
      {:ok, conn} ->
        PowResetPassword.Plug.update_user_password(conn, user_params)

      {:error, conn} ->
        json(conn, %{error: %{message: "Expired Token"}})
    end

  json(conn, %{status: "ok"})
  #end

It returns “ok” even if i put different password in body, but thankfully doesnt change it in DB. Expired token appears when loading user by token fails.

What comes to my mind is to put function for check password inputs if they are equal before updating password but I dont think if it is the best solution. Either nesting case statements looks awful.

Thanks for helping :slight_smile:

Most Liked

mbski

mbski

I read again docs and refactored a little function. Now it looks awful but works, I need to think prettier solution.

  @spec reset_password(Conn.t(), map()) :: Conn.t()
  def reset_password(conn, %{"id" => token, "user" => user_params}) do

    conn
      |> PowResetPassword.Plug.load_user_by_token(token)
      |> case do
          {:ok, conn} ->
            PowResetPassword.Plug.update_user_password(conn, user_params)
            |> case do
              {:error, _changeset, conn} ->
                json(conn, %{message: "Invalid passwords"})

              {:ok, _user, conn} ->
                json(conn, %{message: "Password changed"})
            end

          {:error, conn} ->
            json(conn, %{error: %{message: "Expired Token"}})
        end        
  end

OR

  @spec reset_password(Conn.t(), map()) :: Conn.t()
  def reset_password(conn, %{"id" => token, "user" => user_params}) do

    with {:ok, conn} <- PowResetPassword.Plug.load_user_by_token(conn, token),
         {:ok, _user, conn}  <- PowResetPassword.Plug.update_user_password(conn, user_params) do
          conn
          |> put_status(:ok)
          |> json(%{status: "Password changed"})
    else
          {:error, _changeset, conn} ->
            json(conn, %{error: %{message: "Passwords are not the same"}})

          _ ->
            json(conn, %{error: %{message: "Expired Token"}})
    end
  end

I mark as solution if it works well while testing but I’m still waiting for some advices about tokens cause I am elixir newbie :slight_smile:

Where Next?

Popular in Questions Top

Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; somethi...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

We're in Beta

About us Mission Statement