Joan Gavelán
Joan Gavelán
AEAsh Elixir
Created by Joan Gavelán on 5/2/2025 in #support
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
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
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
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
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
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
}
]
}}
{: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!
9 replies