defmodule PowMultiFactor.Phoenix.ControllerCallbacks do @moduledoc """ Controller callback logic for multi-factor authentication. ### 2FA code not submitted Triggers on `Pow.Phoenix.SessionController.create/2`. When a user with 2FA enabled attempts to sign in without submitting their TOTP token, the session will be cleared, and the user redirected back to `Pow.Phoenix.Routes.session_path/1`. ### User updates account Triggers on `Pow.Phoenix.RegistrationController.update/2` When a user changes their account settings, they are required to confirm a current 2FA token. See `PowMultiFactor.Ecto.Schema` for more. """ use Pow.Extension.Phoenix.ControllerCallbacks.Base alias Pow.Plug alias PowMultiFactor.Plug, as: PowMultiFactorPlug def before_respond(Pow.Phoenix.SessionController, :create, {:ok, conn}, _config) do return_path = routes(conn).session_path(conn, :new) clear_unauthorized(conn, {:ok, conn}, return_path) end def before_respond(Pow.Phoenix.RegistrationController, :update, {:ok, user, conn}, _config) do return_path = routes(conn).registration_path(conn, :edit) halt_unauthorized(conn, {:ok, user, conn}, return_path) end defp clear_unauthorized(conn, success_response, return_path) do case PowMultiFactorPlug.mfa_unauthorized?(conn) do true -> clear_auth(conn) |> go_back(return_path) false -> success_response end end defp halt_unauthorized(conn, success_response, return_path) do case PowMultiFactorPlug.mfa_unauthorized?(conn) do true -> go_back(conn, return_path) false -> success_response end end def clear_auth(conn) do {:ok, conn} = Plug.clear_authenticated_user(conn) conn end defp go_back(conn, return_path) do error = extension_messages(conn).invalid_multi_factor(conn) conn = conn |> Phoenix.Controller.put_flash(:error, error) |> Phoenix.Controller.redirect(to: return_path) {:halt, conn} end end