Ash Authentication Phoenix: Password reset database failure

I have an app that I haven’t updated to Ash 3 yet and one that I have, the one that has been upgraded has an issue when I try to reset a password through the generated web UI.

The email works, but upon trying to set the new password this is the error message, something about jti conflict?

[info] POST /auth/user/password/reset
[debug] Processing with AppWeb.AuthController
Parameters: %{“_csrf_token” => “Z31dKwgdHydrQGQPJwFnexwldyAaB2EBPKmCGtFbZ32Kw4VMwC6TXk83”, “_method” => “POST”, “user” => %{“password” => “[FILTERED]”, “reset_token” => “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY3QiOiJwYXNzd29yZF9yZXNldF93aXRoX3Bhc3N3b3JkIiwiYXVkIjoifj4gNC4wIiwiZXhwIjoxNzE1NzE4NzQzLCJpYXQiOjE3MTU0NTk1NDMsImlzcyI6IkFzaEF1dGhlbnRpY2F0aW9uIHY0LjAuMCIsImp0aSI6IjJ2NzhpbmU1dXUyMm04bWg0azAwMDBjMyIsIm5iZiI6MTcxNTQ1OTU0Mywic3ViIjoidXNlcj9pZD1iN2UyNjY0MC1iNzUxLTQ3ZjgtOGZhOS1lZjU0MDRiMmRjNmQifQ.c9X2nEuYcccuht7L8t7EYKyM3mLyoaUB3cctCBPsC2Q”}}
Pipelines: [:browser]
“supermotel.localhost”
“Set tenant to supermotel”
-----INSPECT-----
Tenant: “supermotel”
[debug] QUERY OK source=“users” db=1.8ms idle=1862.8ms
SELECT u0.“id”, u0.“email”, u0.“hashed_password” FROM “supermotel”.“users” AS u0 WHERE (u0.“id”::uuid = $1::uuid) [“b7e26640-b751-47f8-8fa9-ef5404b2dc6d”]
↳ anonymous fn/3 in AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:696
[debug] QUERY OK db=0.2ms idle=1875.5ms
begin
↳ anonymous fn/3 in Ash.Changeset.with_hooks/3, at: lib/ash/changeset/changeset.ex:2918
[debug] QUERY OK source=“users” db=1.6ms
UPDATE “supermotel”.“users” AS u0 SET “hashed_password” = $1 WHERE (u0.“id” = $2) RETURNING u0.“id” [“$2b$12$anocOFCmCTrdwLOeOgSDuuUYskMd6wGuyxoxHj/MgYEUf69u5iwrS”, “b7e26640-b751-47f8-8fa9-ef5404b2dc6d”]
↳ AshPostgres.DataLayer.update/2, at: lib/data_layer.ex:2484
[debug] QUERY ERROR source=“tokens” db=0.0ms
INSERT INTO “tokens” AS t0 (“subject”,“created_at”,“expires_at”,“jti”,“purpose”,“updated_at”) VALUES ($1,$2,$3,$4,$5,$6) ON CONFLICT (“jti”) DO UPDATE SET “subject” = EXCLUDED.“subject”, “expires_at” = EXCLUDED.“expires_at”, “purpose” = EXCLUDED.“purpose”, “updated_at” = COALESCE(EXCLUDED.“updated_at”, $7) RETURNING “subject”,“jti”,“expires_at”,“purpose”,“extra_data”,“created_at”,“updated_at” [“user?id=b7e26640-b751-47f8-8fa9-ef5404b2dc6d”, ~U[2024-05-11 20:32:41.744782Z], ~U[2024-05-14 20:32:23Z], “2v78ine5uu22m8mh4k0000c3”, “revocation”, ~U[2024-05-11 20:32:41.743630Z], ~U[2024-05-11 20:32:41.744896Z]]
↳ AshPostgres.DataLayer.bulk_create/3, at: lib/data_layer.ex:1579
[debug] QUERY OK db=0.2ms
rollback

To the best of my knowledge this is exact setup as the Getting Started guide shows except for I’ve added Ash multitenency via a schema to my app.

Have you updated to all of the non-rc latest versions as well? Seems strange. If you have a reproduction repo that would be really useful, otherwise I’ll put something together this week.

@zachdaniel I updated to Ash 3.0, same issue. I built a project to reproduce without multitenency and it appears to be working, going to try with multitenency to see if it will reproduce.

1 Like

@zachdaniel here is the repo/branch

Repro steps are:

mix ash_postgres.create
mix ash_postgres.migrate
iex -S mix phx.server

iex> Ash.create!(App.Accounts.Company, %{name: "Taco", domain: "taco"})

Then go to taco.localhost:4000/sign-in, create an account, then log out, then try to reset the account password, the email will get sent to /dev/mailbox, and you can follow the link, but when you try to reset the password an INSERT INTO “tokens” fails:

[info] POST /auth/user/password/reset
“taco.localhost”
[debug] Processing with AppWeb.AuthController
Parameters: %{“_csrf_token” => “EhMIRw5iJQc_Ai4CBR5ALzwRG3kYIAAcqAp0ARvNi5LHTzrDkdj0bByP”, “_method” => “POST”, “user” => %{“password” => “[FILTERED]”, “reset_token” => “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY3QiOiJwYXNzd29yZF9yZXNldF93aXRoX3Bhc3N3b3JkIiwiYXVkIjoifj4gNC4wIiwiZXhwIjoxNzE3MjAxNTA4LCJpYXQiOjE3MTY5NDIzMDgsImlzcyI6IkFzaEF1dGhlbnRpY2F0aW9uIHY0LjAuMCIsImp0aSI6IjJ2OXNycm4xaDRoOXI3bGs1azAwMDJwNCIsIm5iZiI6MTcxNjk0MjMwOCwic3ViIjoidXNlcj9pZD1kZDVjMzZlMS04ZGI1LTQyMDQtYjUzNS1kMDk1NTA5NDBhZTUifQ.NC2W-IAHBWj-3oPGJph1Wr5dIIL7aHwv_DGLzAN3rsQ”}}
Pipelines: [:browser]
“Set tenant to taco”
[debug] QUERY OK source=“users” db=0.7ms idle=1157.2ms
SELECT u0.“id”, u0.“email”, u0.“hashed_password” FROM “taco”.“users” AS u0 WHERE (u0.“id”::uuid = $1::uuid) [“dd5c36e1-8db5-4204-b535-d09550940ae5”]
↳ anonymous fn/3 in AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:749
[debug] QUERY OK db=0.1ms idle=1158.4ms
begin
↳ anonymous fn/3 in Ash.Changeset.with_hooks/3, at: lib/ash/changeset/changeset.ex:2963
[debug] QUERY OK source=“users” db=0.7ms
UPDATE “taco”.“users” AS u0 SET “hashed_password” = $1 WHERE (u0.“id” = $2) RETURNING u0.“hashed_password” [“$2b$12$fmj7fgqSd9qq1ZtiL0zsRuBe2SWRk0As2d8d0VLCk7XoSS1C9uhXC”, “dd5c36e1-8db5-4204-b535-d09550940ae5”]
↳ AshPostgres.DataLayer.update/2, at: lib/data_layer.ex:2649
[debug] QUERY ERROR source=“tokens” db=0.0ms
INSERT INTO “tokens” AS t0 (“subject”,“created_at”,“expires_at”,“jti”,“purpose”,“updated_at”) VALUES ($1,$2,$3,$4,$5,$6) ON CONFLICT (“jti”) DO UPDATE SET “subject” = EXCLUDED.“subject”, “expires_at” = EXCLUDED.“expires_at”, “purpose” = EXCLUDED.“purpose”, “updated_at” = COALESCE(EXCLUDED.“updated_at”, $7) RETURNING “jti”,“subject”,“expires_at”,“purpose”,“extra_data”,“created_at”,“updated_at” [“user?id=dd5c36e1-8db5-4204-b535-d09550940ae5”, ~U[2024-05-29 00:25:59.760930Z], ~U[2024-06-01 00:25:08Z], “2v9srrn1h4h9r7lk5k0002p4”, “revocation”, ~U[2024-05-29 00:25:59.760924Z], ~U[2024-05-29 00:25:59.761029Z]]
↳ AshPostgres.DataLayer.bulk_create/3, at: lib/data_layer.ex:1745
[debug] QUERY OK db=0.1ms
rollback

I assume you’re doing something fancy to make this actually work, as IIRC it doesn’t work by default.

EDIT: got it working

1 Like

Alright, I’ve just pushed a commit to ash_authentication that should fix this. Was an internal mechanical error :slight_smile:

You can try out main, or CI should cut a new release on its own once its done building.

1 Like