Ash FrameworkAF
Ash Framework9mo ago
16 replies
Joan Gavelán

Custom Authentication Flow with AshAuthentication in Phoenix + React (Inertia.js)

Hi everyone! I've been implementing a custom authentication flow using AshAuthentication with Phoenix and React via Inertia.js. I wanted to share my approach and ask for feedback, especially regarding password reset functionality.

Working Authentication Actions


So far, I've successfully implemented the following actions defined by the AshAuthentication generator in my User Resource:

define :register_with_password
define :sign_in_with_password
define :request_password_reset_token
define :reset_password_with_token

Registration Controller


Here's how I'm handling registration:

def create(conn, params) do
  case Accounts.register_with_password(params) do
    {:ok, _user} ->
      conn
      |> redirect(to: ~p"/successfully-registered")

    {:error, error} ->
      conn
      |> assign_errors(error)
      |> redirect(to: ~p"/register")
  end
end

Login Controller


And here's the login implementation:

def create(conn, params) do
  case Accounts.sign_in_with_password(params) do
    {:ok, user} ->
      UserAuth.log_in(conn, user)

    {:error, _error} ->
      conn
      |> put_flash(:error, "Invalid email or password")
      |> redirect(to: ~p"/login")
  end
end

Password Reset Flow


I've implemented the first part of the password reset flow - requesting a reset token:

def create(conn, params) do
  Accounts.request_password_reset_token(params)

  conn
  |> put_flash(
    :info,
    "If your email is in our system, you will receive an email with instructions to reset your password."
  )
  |> redirect(to: ~p"/login")
end

Issue with Password Reset


I'm trying to implement the controller to update the password, but I'm getting an error:

def update(conn, params) do
  Accounts.reset_password_with_token(params) |> IO.inspect()

  conn
  |> redirect(to: ~p"/password-reset/#{params["reset_token"]}")
end

The error I'm getting is:

{:error,
 %Ash.Error.Invalid{
   errors: [
     %Ash.Error.Invalid.InvalidPrimaryKey{
       resource: Contactly.Accounts.User,
       value: %{
         "password" => "newpass",
         "password_confirmation" => "newpass",
         "reset_token" => "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY3QiOiJyZXNldF9wYXNzd29yZF93aXRoX3Rva2VuIiwiYXVkIjoifj4gNC43IiwiZXhwIjoxNzQ2NDcxMzU2LCJpYXQiOjE3NDYyMTIxNTYsImlzcyI6IkFzaEF1dGhlbnRpY2F0aW9uIHY0LjcuNiIsImp0aSI6IjMwdHNsZDM4cjY4YnVzdmE4azAwN2YyNyIsIm5iZiI6MTc0NjIxMjE1Niwic3ViIjoidXNlcj9pZD01ZDdlZDRiNS1jMmM5LTQ0MTQtYWRmMi0wMzc0ZDdmMmIxZGEifQ.UbkDMiFAm9jbydOpA9dIiYRGK5vGrspb-jGNic25eL8"
       },
       splode: Ash.Error,
       bread_crumbs: [],
       vars: [],
       path: [],
       stacktrace: #Splode.Stacktrace<>,
       class: :invalid
     }
   ]
 }}

It seems like there's an issue with a "primary key", but I'm not sure what this means since I am passing all the expected parameters (password, password_confirmation, token).

So, how should I properly implement this?

Thanks in advance for any help or insights!
Was this page helpful?