ashauthentication: possible bugs?
frankdugan3:
I have a couple errors coming up with AshAuthentication, not sure if they’re bugs or me doing something wrong.
-
If I disable registration:
I get this error:strategies do password :password do identity_field :email registration_enabled? false
[error] #PID<0.22797.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.22796.0>, stream id 1) terminated Server: localhost:4000 (http) Request: GET /sign-in ** (exit) an exception was raised: ** (KeyError) key :type not found in: nil. If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map (ash_phoenix 1.2.10) lib/ash_phoenix/form/form.ex:396: AshPhoenix.Form.for_action/3 (ash_authentication_phoenix 1.6.4) lib/ash_authentication_phoenix/components/password/register_form.ex:59: AshAuthentication.Phoenix.Components.Password.RegisterForm.update/2 (phoenix_live_view 0.18.18) lib/phoenix_live_view/utils.ex:484: Phoenix.LiveView.Utils.maybe_call_update!/3 (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:661: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6 (elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3 (stdlib 4.2) maps.erl:411: :maps.fold_1/3 (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:635: Phoenix.LiveView.Diff.render_pending_components/6 (phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:146: Phoenix.LiveView.Diff.render/3 (phoenix_live_view 0.18.18) lib/phoenix_live_view/static.ex:252: Phoenix.LiveView.Static.to_rendered_content_tag/4 (phoenix_live_view 0.18.18) lib/phoenix_live_view/static.ex:135: Phoenix.LiveView.Static.render/3 (phoenix_live_view 0.18.18) lib/phoenix_live_view/controller.ex:39: Phoenix.LiveView.Controller.live_render/3 (phoenix 1.7.2) lib/phoenix/router.ex:430: Phoenix.Router.__call__/5 (hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint.plug_builder_call/2 (hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint."call (overridable 3)"/2 (hsm 0.8.0) lib/plug/debugger.ex:136: HsmWeb.Endpoint."call (overridable 4)"/2 (hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint.call/2 (phoenix 1.7.2) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4 (plug_cowboy 2.6.1) lib/plug/cowboy/handler.ex:11: Plug.Cowboy.Handler.init/2 (cowboy 2.9.0) /home/frank/git/hsm-tmp-release-branch/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2 (cowboy 2.9.0) /home/frank/git/hsm-tmp-release-branch/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
- When I try to open a password reset link, I get the following error:
frankdugan3:
[error] #PID<0.24374.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.24373.0>, stream id 1) terminated
Server: localhost:4000 (http)
Request: GET /password-reset/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY3QiOiJwYXNzd29yZF9yZXNldF93aXRoX3Bhc3N3b3JkIiwiYXVkIjoifj4gMy4xMCIsImV4cCI6MjYxMjcxNTU4MywiaWF0IjoxNjc5NTk1NTgzLCJpc3MiOiJBc2hBdXRoZW50aWNhdGlvbiB2My4xMC4yIiwianRpIjoiMnQ3aHVpNXBiZ2djYzducTlzMDA5bmk0IiwibmJmIjoxNjc5NTk1NTgzLCJzdWIiOiJ1c2VyP2lkPWEzOGUzMzJhLTQ5ODctNTljNS1iZTliLTk4MmMyYTRjNDBhOCJ9.Qifx4rtzcKVxWAbT6eflC8yLM9egUoyL93liJhvDnSM
** (exit) an exception was raised:
** (ArgumentError) :socket is a reserved assign by LiveView and it cannot be set directly
(phoenix_live_view 0.18.18) lib/phoenix_component.ex:1245: Phoenix.Component.validate_assign_key!/1
(phoenix_live_view 0.18.18) lib/phoenix_component.ex:1196: Phoenix.Component.assign/3
(stdlib 4.2) maps.erl:411: :maps.fold_1/3
(ash_authentication_phoenix 1.6.4) lib/ash_authentication_phoenix/components/reset/form.ex:76: AshAuthentication.Phoenix.Components.Reset.Form.update/2
(phoenix_live_view 0.18.18) lib/phoenix_live_view/utils.ex:484: Phoenix.LiveView.Utils.maybe_call_update!/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:661: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
(elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(stdlib 4.2) maps.erl:411: :maps.fold_1/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:635: Phoenix.LiveView.Diff.render_pending_components/6
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:146: Phoenix.LiveView.Diff.render/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/static.ex:252: Phoenix.LiveView.Static.to_rendered_content_tag/4
(phoenix_live_view 0.18.18) lib/phoenix_live_view/static.ex:135: Phoenix.LiveView.Static.render/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/controller.ex:39: Phoenix.LiveView.Controller.live_render/3
(phoenix 1.7.2) lib/phoenix/router.ex:430: Phoenix.Router.__call__/5
(hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint.plug_builder_call/2
(hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint."call (overridable 3)"/2
(hsm 0.8.0) lib/plug/debugger.ex:136: HsmWeb.Endpoint."call (overridable 4)"/2
(hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint.call/2
(phoenix 1.7.2) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4
(plug_cowboy 2.6.1) lib/plug/cowboy/handler.ex:11: Plug.Cowboy.Handler.init/2
frankdugan3:
Auth config:
authentication do
api Hsm.Ash.Authentication
strategies do
password :password do
identity_field :email
registration_enabled? false
resettable do
sender Hsm.Ash.Authentication.Senders.SendPasswordResetEmail
end
end
end
tokens do
enabled? true
token_resource Hsm.Ash.Authentication.UserToken
signing_secret Hsm.Authentication.Secrets
end
end
frankdugan3:
Lib versions:
ash 2.6.27 2.6.27 Up-to-date
ash_authentication 3.10.2 3.10.2 Up-to-date
ash_authentication_phoenix 1.6.4 1.6.4 Up-to-date
ash_graphql 0.23.1 0.23.1 Up-to-date
ash_phoenix 1.2.10 1.2.10 Up-to-date
ash_postgres 1.3.17 1.3.17 Up-to-date
phoenix 1.7.2 1.7.2 Up-to-date
phoenix_ecto 4.4.0 4.4.0 Up-to-date
phoenix_html 3.3.1 3.3.1 Up-to-date
phoenix_live_dashboard 0.7.2 0.7.2 Up-to-date
phoenix_live_reload 1.4.1 1.4.1 Up-to-date
phoenix_live_view 0.18.18 0.18.18 Up-to-date
frankdugan3:
I think the second one might be due to recent changes in
phoenix_live_view
that has more stringent checks on reserved assigns, like socket.
ZachDaniel:
🤔 interesting
ZachDaniel:
ah, yeah
ZachDaniel:
it looks like we’re using
@socket
all over
ZachDaniel:
damn
ZachDaniel:
So:
- make the form handle disabled registration
-
eliminate all usages of passing the
@socket
around
ZachDaniel:
well
ZachDaniel:
Does that mean that
@socket
is available everywhere and doesn’t need to be provided?
frankdugan3:
I haven’t looked at the code, but based on why I would pass it around in stuff I’ve done before, I would guess it’s for the Route helpers. If that’s the case, they can also be passed the endpoint instead of the socket.
ZachDaniel:
can you try that branch out?
frankdugan3:
Yeah, is there a trick to using an unmerged PR in mix?
ZachDaniel:
just use the branch
ZachDaniel:
component-fixes
frankdugan3:
OK, looks like the password reset link works now. Still getting an error on the login form if registration is disabled.
frankdugan3:
[error] #PID<0.3447.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.3446.0>, stream id 1) terminated
Server: localhost:4000 (http)
Request: GET /sign-in
** (exit) an exception was raised:
** (KeyError) key :type not found in: nil. If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map
(ash_phoenix 1.2.11) lib/ash_phoenix/form/form.ex:396: AshPhoenix.Form.for_action/3
(ash_authentication_phoenix 1.6.4) lib/ash_authentication_phoenix/components/password/register_form.ex:59: AshAuthentication.Phoenix.Components.Password.RegisterForm.update/2
(phoenix_live_view 0.18.18) lib/phoenix_live_view/utils.ex:484: Phoenix.LiveView.Utils.maybe_call_update!/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:661: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
(elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(stdlib 4.2) maps.erl:411: :maps.fold_1/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:635: Phoenix.LiveView.Diff.render_pending_components/6
(phoenix_live_view 0.18.18) lib/phoenix_live_view/diff.ex:146: Phoenix.LiveView.Diff.render/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/static.ex:252: Phoenix.LiveView.Static.to_rendered_content_tag/4
(phoenix_live_view 0.18.18) lib/phoenix_live_view/static.ex:135: Phoenix.LiveView.Static.render/3
(phoenix_live_view 0.18.18) lib/phoenix_live_view/controller.ex:39: Phoenix.LiveView.Controller.live_render/3
(phoenix 1.7.2) lib/phoenix/router.ex:430: Phoenix.Router.__call__/5
(hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint.plug_builder_call/2
(hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint."call (overridable 3)"/2
(hsm 0.8.0) lib/plug/debugger.ex:136: HsmWeb.Endpoint."call (overridable 4)"/2
(hsm 0.8.0) lib/hsm_web/endpoint.ex:1: HsmWeb.Endpoint.call/2
(phoenix 1.7.2) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4
(plug_cowboy 2.6.1) lib/plug/cowboy/handler.ex:11: Plug.Cowboy.Handler.init/2
(cowboy 2.9.0) /home/frank/git/hsm-tmp-release-branch/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
(cowboy 2.9.0) /home/frank/git/hsm-tmp-release-branch/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
ZachDaniel:
Oh, yeah right I didn’t fix that
ZachDaniel:
I’m a bit confused by the set up there
ZachDaniel:
Might need <@346791515923939328> to weigh in. It looks like we need to only show the register form if one of the actions supports it. But I feel like the typespecs don’t line up with reality so I’m a bit confused. I can’t find
AshAuthentication.Strategy.t()
frankdugan3:
The web error might be a little more helpful.

frankdugan3:
I think it needs to handle the action being nil because it doesn’t exist when registration is disabled.
ZachDaniel:
Yeah, but it should be disabled at a higher point
ZachDaniel:
I.e not even rendering that component
frankdugan3:
Gotchya. Yeah, I have no familiarity w/ the codebase, so I’ll probably stop guessing. 😅
frankdugan3:
Interesting, this also affects the migration generator:
Also getting a migration generator error, seems to happen whether or not I disable registration:
mix ash_postgres.generate_migrations --name add_user_and_token
Compiling 115 files (.ex)
10:15:35.984 [warning] You have specified a default value for a type that cannot be explicitly
converted to an Ecto default:
`[]`
The default value in the migration will be set to `nil` and you can edit
your migration accordingly.
To prevent this warning, implement the `EctoMigrationDefault` protocol
for the appropriate Elixir type in your Ash project, or configure its
default value in `migration_defaults` in the postgres section. Use `\"nil\"`
for no default.
** (KeyError) key :source not found in: nil. If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map
(ash_postgres 1.3.18) lib/migration_generator/migration_generator.ex:2057: anonymous fn/2 in AshPostgres.MigrationGenerator.check_constraints/1
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash_postgres 1.3.18) lib/migration_generator/migration_generator.ex:2052: anonymous fn/2 in AshPostgres.MigrationGenerator.check_constraints/1
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash_postgres 1.3.18) lib/migration_generator/migration_generator.ex:2004: AshPostgres.MigrationGenerator.do_snapshot/3
(ash_postgres 1.3.18) lib/migration_generator/migration_generator.ex:1994: AshPostgres.MigrationGenerator.get_snapshots/2
(elixir 1.14.3) lib/enum.ex:4249: Enum.flat_map_list/2
(elixir 1.14.3) lib/enum.ex:4250: Enum.flat_map_list/2
ZachDaniel:
🤔
ZachDaniel:
I wonder which attribute we’re adding with
[]
as the value
frankdugan3:
Crashes before writing any files, so hard to say from my end.
ZachDaniel:
Hmm…that warning wouldn’t cause a crash
ZachDaniel:
Oh
ZachDaniel:
So dumb sorry lol
ZachDaniel:
I just looked at the warning
ZachDaniel:
…do you have any check constraints?
frankdugan3:
Bog standard on the token:
defmodule Hsm.Ash.Authentication.UserToken do
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
authorizers: [Ash.Policy.Authorizer],
extensions: [AshAuthentication.TokenResource]
postgres do
table "user_tokens"
repo Hsm.Repo
end
token do
api Hsm.Ash.Authentication
end
policies do
bypass AshAuthentication.Checks.AshAuthenticationInteraction do
authorize_if always()
end
end
end
User isn’t too fancy:
defmodule Hsm.Ash.Authentication.User do
@moduledoc false
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
authorizers: [Ash.Policy.Authorizer],
notifiers: [
Ash.Notifier.PubSub
],
extensions: [
AshAuthentication
]
import Hsm.Ash.PolicyAuthorizer.Checks
import Hsm.Ash.Validations
alias Hsm.Ash.Authentication.UserRole
resource do
description ""
end
postgres do
table "users"
repo Hsm.Repo
end
authentication do
api Hsm.Ash.Authentication
strategies do
password :password do
identity_field :email
# registration_enabled? false
resettable do
sender Hsm.Ash.Authentication.Senders.SendPasswordResetEmail
end
end
end
tokens do
enabled? true
token_resource Hsm.Ash.Authentication.UserToken
signing_secret Hsm.Authentication.Secrets
end
end
pub_sub do
# ...
end
attributes do
attribute :email, :ci_string,
allow_nil?: false,
sensitive?: true,
constraints: [
max_length: 160
]
attribute :roles, {:array, UserRole}, allow_nil?: false
attribute :hashed_password, :string, sensitive?: true, allow_nil?: false
attribute :active, :boolean, allow_nil?: false, default: true
uuid_primary_key :id
end
identities do
identity :email, [:email]
end
relationships do
has_one :employee, Hsm.Ash.Employees.Employee,
destination_attribute: :user_id,
api: Hsm.Ash.Employees
end
aggregates do
first :employee_code, :employee, :code
first :employee_name_formal, :employee, :name_formal
end
validations do
validate valid_email(:email)
end
actions do
# ...
end
code_interface do
# ...
end
policies do
bypass AshAuthentication.Checks.AshAuthenticationInteraction do
authorize_if always()
end
# ...
end
end
frankdugan3:
I’ve already manually created the migrations, so it’s not a huge rush to figure that one out.
ZachDaniel:
Honestly I think that might be a different resource entirely
frankdugan3:
Oh, that’s totally possible. Didn’t even think of that, since I haven’t been using the generator yet. I just wanted to figure out a diff for the auth stuff.
ZachDaniel:
We loop over check constraints and check for an existing matching attribute
frankdugan3:
So never mind on that, will sleuth that on my own later. Only remaining issue w/ auth is disabling the registration in AshAuthenticationPhoenix. It’s a pretty smooth experience so far, loving it! 😄
jart:
Hey folks. So the reason the socket gets passed around is for the otp_app that we pull from the endpoint.
ZachDaniel:
But it seems like
@socket
is just always available anyway
jart:
Okay that surprises me but ¯_(ツ)_/¯
ZachDaniel:
Same here
ZachDaniel:
But if you try out the dev server on my branch it all works
jart:
It makes sense that it would blow up with registration disabled now that I think about it because AAP isn’t aware that that’s a thing and assumes that registration and sign in are always enabled.
jart:
Should be fixable in
Components.Password
ZachDaniel:
Yeah, I was looking there, but have some questions.
ZachDaniel:
reset_enabled? =
Enum.any?(strategy.resettable) && override_for(assigns.overrides, :reset_toggle_text)
ZachDaniel:
I’m a bit confused about
strategy.resettable
ZachDaniel:
and the
Enum.any?
ZachDaniel:
Also for the life of me I can’t find this type:
required(:strategy) => AshAuthentication.Strategy.t(),
ZachDaniel:
Is that autogenerated by it being a protocol?
ZachDaniel:
Trying to figure out how to do basically the same thing for if you can register
jart:
- Yeah it’s because resettable is an entity on the password strategy.
- Yes, it’s generated by defprotocol.
ZachDaniel:
ohhh I see. I have a hack for that:
def transform(read) do
if read.pagination do
if is_list(read.pagination) do
{:ok, %{read | pagination: List.last(read.pagination) || false}}
else
{:ok, %{read | pagination: read.pagination}}
end
else
{:ok, %{read | pagination: false}}
end
end
ZachDaniel:
If you have a “singleton” entity
ZachDaniel:
but I think we need to make that config in the DSL really
ZachDaniel:
okay so I should be able to fix that
ZachDaniel:
Okay <@433654314175692800> that branch should have that fix now
frankdugan3:
Success!

frankdugan3:
I also mixed in the stored tokens like you have on AshHQ, works perfect!
frankdugan3:
I’ll mark this as solved and will keep an eye out for the PR getting merged/released.
ZachDaniel:
🥳