defmodule PhoenixKitWeb.Users.Session do @moduledoc """ Controller for handling user session management. This controller manages user login and logout operations, including: - Creating new sessions via email/password authentication - Handling post-registration and password update flows - Session termination (logout) - GET-based logout for direct URL access ## Security Features - Prevents user enumeration by not disclosing whether an email is registered - Supports remember me functionality via UserAuth module - Session renewal on login/logout to prevent fixation attacks """ use PhoenixKitWeb, :controller alias PhoenixKit.Users.Auth alias PhoenixKit.Utils.Routes alias PhoenixKitWeb.Users.Auth, as: UserAuth def create(conn, %{"_action" => "registered"} = params) do create(conn, params, "Account created successfully!") end def create(conn, %{"_action" => "password_updated"} = params) do conn |> put_session(:user_return_to, Routes.path("/users/settings")) |> create(params, "Password updated successfully!") end def create(conn, params) do create(conn, params, "Welcome back!") end defp create(conn, %{"user" => user_params}, info) do %{"email" => email, "password" => password} = user_params case Auth.get_user_by_email_and_password(email, password) do %Auth.User{is_active: false} -> # Valid credentials but account is inactive conn |> put_flash( :error, "Your account is currently inactive. Please contact the team if you believe this is an error." ) |> put_flash(:email, String.slice(email, 0, 160)) |> redirect(to: Routes.path("/users/log-in")) %Auth.User{} = user -> # Valid credentials and active account conn |> put_flash(:info, info) |> UserAuth.log_in_user(user, user_params) nil -> # Invalid credentials (wrong email or password) # In order to prevent user enumeration attacks, don't disclose whether the email is registered. conn |> put_flash(:error, "Invalid email or password") |> put_flash(:email, String.slice(email, 0, 160)) |> redirect(to: Routes.path("/users/log-in")) end end def delete(conn, _params) do conn |> put_flash(:info, "Logged out successfully.") |> UserAuth.log_out_user() end # Support GET logout for direct URL access def get_logout(conn, _params) do conn |> put_flash(:info, "Logged out successfully.") |> UserAuth.log_out_user() end end