Guy14

Guy14

Hello community!

I encounter a warning saying that AshAuthentication.Errors.AuthenticationFailed does not implement the AshPhoenix.FormData.Error protocol while running tests (with an voluntary wrong password) for a Phoenix Liveview.

...12:06:14.730 [warning] Unhandled error in form submission for Prepair.AshDomains.Accounts.User.change_password

This error was unhandled because AshAuthentication.Errors.AuthenticationFailed does not implement the `AshPhoenix.FormData.Error` protocol.

** (AshAuthentication.Errors.AuthenticationFailed) Authentication failed

I’ve read this issue: This error was unhandled because it did not implement the `AshPhoenix.FormData.Error` protocol. · Issue #516 · ash-project/ash · GitHub and tried the proposed solution, but it didn’t worked for me.

Here is my change_password action:

update :change_password do
      # Use this action to allow users to change their password by providing
      # their current password and a new password.

      require_atomic? false
      accept []
      argument :current_password, :string, sensitive?: true, allow_nil?: false

      argument :password, :string,
        sensitive?: true,
        allow_nil?: false

      argument :password_confirmation, :string,
        sensitive?: true,
        allow_nil?: false

      validate confirm(:password, :password_confirmation)

      validate {AshAuthentication.Strategy.Password.PasswordValidation,
                strategy_name: :password, password_argument: :current_password}

      change {AshAuthentication.Strategy.Password.HashPasswordChange,
              strategy_name: :password}
    end

I tried to add change set_context(%{strategy_name: :password}) before the other change call, but it didn’t solved the warning.

Here are the current uses and imports on my resource:

defmodule Prepair.AshDomains.Accounts.User do
  use Ash.Resource,
    domain: Prepair.AshDomains.Accounts,
    data_layer: AshPostgres.DataLayer,
    authorizers: [Ash.Policy.Authorizer],
    extensions: [AshAuthentication]

  alias Prepair.AshDomains.Profiles.Profile

  import Prepair.AshDomains.ValidationMacros

Here are the current uses and imports in my domain (which exposes the code interfaces then used in the liveview).

I wonder if I should add AshPhoenix there.

defmodule Prepair.AshDomains.Accounts do
  use Ash.Domain

And here is my handle_event function for the save action in the Liveview:

def handle_event("save", %{"user" => params}, socket) do
    current_user = socket.assigns.current_user

    form =
      AshPhoenix.Form.for_update(current_user, :change_password,
        domain: Accounts,
        as: "user"
      )
      |> AshPhoenix.Form.validate(params)

    case AshPhoenix.Form.submit(form, params: params) do
      {:ok, _user} ->
        {:noreply,
         socket
         |> put_flash(:info, "Password updated successfully")
         |> redirect(to: ~p"/")}

      {:error, form} ->
        {:noreply,
         socket |> assign(:form, to_form(form)) |> assign(check_errors: true)}
    end
  end

Showing Posts 1 to 5

FlyingNoodle

FlyingNoodle

  1. You need the pass the current_user as actor.
  2. You don’t need the call to validate since submit will validate your form anyway.
  3. I assume you assign you form to the socket in some other callback. In that case you can just do: AshPhoenix.Form.submit(socket.assigns.my_form_that_i_assigned, params: params, actor: current_user)
Guy14

Guy14 OP

Thanks for you reply @FlyingNoodle !

I’ve done the refactors you adviced, the test still passes (and my code is improved), but I still have the warning that AshAuthentication errors are not handled by AshPheonix.FormData.Error.

Here is my full current liveview:

defmodule PrepairWeb.UserUpdatePasswordLive do
  use PrepairWeb, :live_view
  use Gettext, backend: PrepairWeb.Gettext

  alias Prepair.AshDomains.Accounts

  def render(assigns) do
    ~H"""
    <div class="mx-auto max-w-sm">
      <.header class="text-center">
        <%= gettext("Update your password") %>

        <:actions>
          <.link patch={~p"/"}>
            <.button><%= gettext("Go Back Home") %></.button>
          </.link>
        </:actions>
      </.header>

      <.simple_form
        for={@update_password_form}
        id="update_password_form"
        phx-submit="save"
        phx-change="validate"
      >
        <.error :if={@check_errors}>
          <%= gettext("Oops, something went wrong! Please check the errors below.") %>
        </.error>

        <.input
          field={@update_password_form[:email]}
          type="hidden"
          id="hidden_user_email"
          value={@current_email}
        />

        <.input
          field={@update_password_form[:current_password]}
          type="password"
          label={gettext("Current password")}
          required
        />

        <.input
          field={@update_password_form[:password]}
          type="password"
          label={gettext("New password")}
          required
        />

        <.input
          field={@update_password_form[:password_confirmation]}
          type="password"
          label={gettext("New password confirmation")}
          required
        />

        <:actions>
          <.button phx-disable-with={gettext("Updating password...")} class="w-full">
            <%= gettext("Update password") %>
          </.button>
        </:actions>
      </.simple_form>
    </div>
    """
  end

  def mount(_params, _session, socket) do
    current_user = socket.assigns.current_user

    form =
      AshPhoenix.Form.for_update(current_user, :change_password,
        domain: Accounts,
        as: "user"
      )

    socket =
      socket
      |> assign(check_errors: false)
      |> assign(:current_email, current_user.email)
      |> assign(:update_password_form, to_form(form))

    {:ok, socket}
  end

  def handle_event("save", %{"user" => params}, socket) do
    current_user = socket.assigns.current_user
    form = socket.assigns.update_password_form

    case AshPhoenix.Form.submit(form,
           params: params,
           actor: current_user
         ) do
      {:ok, _user} ->
        {:noreply,
         socket
         |> put_flash(:info, "Password updated successfully")
         |> redirect(to: ~p"/")}

      {:error, form} ->
        {:noreply,
         socket
         |> assign(:update_password_form, to_form(form))
         |> assign(check_errors: true)}
    end
  end

  # TODO: transform to a modal from the current profile page
  def handle_event("validate", %{"user" => params}, socket) do
    current_user = socket.assigns.current_user

    form =
      AshPhoenix.Form.for_update(current_user, :change_password,
        domain: Accounts,
        as: "user"
      )
      |> AshPhoenix.Form.validate(params)

    {:noreply, assign(socket, :update_password_form, to_form(form))}
  end
end

FlyingNoodle

FlyingNoodle

can you show us your policies block in the user resource?

Guy14

Guy14 OP

It’s a very basic one for now:

policies do
    bypass AshAuthentication.Checks.AshAuthenticationInteraction do
      authorize_if always()
    end

    policy always() do
      authorize_if always()
    end
  end

For me the issue is not there, it’s in how to translate an AshAuthentication error to be able to output it in the form (to give the user a feedback).

To clarify: it’s normal that my test raises an AshAuthentication error. Regarding my :change_password action, I check the User’s current_password is valid before acting the password change, even if the user is already connected (it’s just an over-validation to ensure nobody else than the user did that password change in case someone just left his computer open without locking it).

So the error is normal in my test, but I would just like it to be translated into the form.

Guy14

Guy14 OP

I ended by implementing the AshPhoenix.FormData.Error for AshAuthentication.Errors.AuthenticationFailed. I’m not sure it is a good practice, but for now it does the job.

defimpl AshPhoenix.FormData.Error,
  for: AshAuthentication.Errors.AuthenticationFailed do
  def to_form_error(error) do
    {error.field, "authentication failed", []}
  end
end
— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
ChrisAmelia
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication): toke...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews