diff --git a/lib/ash_authentication/strategies/password/actions.ex b/lib/ash_authentication/strategies/password/actions.ex index 6cd229e..ae08fc9 100644 --- a/lib/ash_authentication/strategies/password/actions.ex +++ b/lib/ash_authentication/strategies/password/actions.ex @@ -7,7 +7,7 @@ defmodule AshAuthentication.Strategy.Password.Actions do """ alias Ash.{Changeset, Error.Invalid.NoSuchAction, Query, Resource} - alias AshAuthentication.{Errors, Info, Jwt, Strategy.Password} + alias AshAuthentication.{Errors, Info, Jwt, Strategy.Password, TokenResource} @doc """ Attempt to sign in a user. @@ -236,6 +236,11 @@ defmodule AshAuthentication.Strategy.Password.Actions do } }) |> Changeset.for_update(resettable.password_reset_action_name, params) + |> Changeset.after_action(fn _changeset, record -> + token_resource = Info.authentication_tokens_token_resource!(resource) + :ok = TokenResource.revoke(token_resource, token) + {:ok, record} + end) |> Ash.update(options) else {:error, %Changeset{} = changeset} -> {:error, changeset} diff --git a/test/ash_authentication/strategies/password/actions_test.exs b/test/ash_authentication/strategies/password/actions_test.exs index d071eed..5f6206e 100644 --- a/test/ash_authentication/strategies/password/actions_test.exs +++ b/test/ash_authentication/strategies/password/actions_test.exs @@ -5,6 +5,7 @@ defmodule AshAuthentication.Strategy.Password.ActionsTest do alias AshAuthentication.{ Errors.AuthenticationFailed, + Errors.InvalidToken, Info, Jwt, Strategy.Password, @@ -246,5 +247,22 @@ defmodule AshAuthentication.Strategy.Password.ActionsTest do assert user.hashed_password != updated_user.hashed_password assert strategy.hash_provider.valid?(new_password, updated_user.hashed_password) end + + test "the token can only be used once" do + user = build_user() + {:ok, strategy} = Info.strategy(Example.User, :password) + assert {:ok, token} = Password.reset_token_for(strategy, user) + + new_password = password() + + params = %{ + "reset_token" => token, + "password" => new_password, + "password_confirmation" => new_password + } + + assert {:ok, _} = Actions.reset(strategy, params, []) + assert {:error, %InvalidToken{}} = Actions.reset(strategy, params, []) + end end end