### Create TOTP Setup LiveView
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp.md
Implement a LiveView to render the TOTP setup component for authenticated users.
```elixir
# lib/my_app_web/live/totp_setup_live.ex
defmodule MyAppWeb.TotpSetupLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, strategy} = AshAuthentication.Info.strategy(MyApp.Accounts.User, :totp)
{:ok, assign(socket, strategy: strategy)}
end
def render(assigns) do
~H"""
Set Up Two-Factor Authentication
<.live_component
module={AshAuthentication.Phoenix.Components.Totp.SetupForm}
id="totp-setup"
strategy={@strategy}
current_user={@current_user}
/>
"""
end
end
```
--------------------------------
### Start Phoenix Server Command
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/get-started.md
This command starts the Phoenix development server. Visit `localhost:4000` in your browser to see the application.
```bash
mix phx.server
```
--------------------------------
### Add TOTP Setup Route
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp.md
Register the setup LiveView in the router, ensuring it is protected by authentication.
```elixir
scope "/", MyAppWeb do
pipe_through [:browser, :require_authenticated_user]
live "/settings/totp", TotpSetupLive
end
```
--------------------------------
### Install Ash Authentication Phoenix with Igniter
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/get-started.md
Use the Igniter installer to automatically configure the project for Ash Authentication.
```sh
mix igniter.install ash_authentication_phoenix
```
```sh
mix igniter.install ash_authentication
# and then run
mix igniter.install ash_authentication_phoenix
```
--------------------------------
### Configure TOTP Two-Factor Authentication Routes
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Set up routes for TOTP verification and setup pages. Ensure the user is authenticated for the TOTP setup.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
scope "/", MyAppWeb do
pipe_through :browser
# TOTP verification page (after password sign-in)
totp_2fa_route MyApp.Accounts.User, :totp,
path: "/totp-verify",
auth_routes_prefix: "/auth"
# TOTP setup page (for authenticated users)
ash_authentication_live_session :totp_setup,
on_mount: {MyAppWeb.LiveUserAuth, :live_user_required} do
totp_setup_route MyApp.Accounts.User, :totp,
path: "/totp-setup",
auth_routes_prefix: "/auth"
end
end
end
```
--------------------------------
### Add TOTP Setup Route
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp-2fa.md
Define a route for the TOTP setup LiveView page within your Phoenix router. This uses `ash_authentication_live_session` to ensure the user is authenticated before accessing the setup page.
```elixir
scope "/", MyAppWeb do
pipe_through :browser
ash_authentication_live_session :authenticated,
on_mount: [{MyAppWeb.LiveUserAuth, :live_user_required}] do
live "/auth/totp/setup", TotpSetupLive
end
end
```
--------------------------------
### Authentication Metadata Examples
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp-2fa.md
Illustrates how authentication strategies are recorded in user metadata after sign-in and how TOTP verification timestamps are stored.
```elixir
# After password sign-in
user.__metadata__.authentication_strategies
#=> [:password]
# After TOTP sign-in
user.__metadata__.authentication_strategies
#=> [:totp]
# After TOTP verification (includes timestamp)
user.__metadata__.totp_verified_at
#=> ~U[2024-01-15 10:30:00Z]
```
--------------------------------
### Configure Router with Authentication Hooks
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/liveview.md
Integrate the `LiveUserAuth` hooks into your Phoenix router to enforce authentication requirements for specific routes. This example shows required and optional authentication setups.
```elixir
# lib/my_app_web/router.ex
# ...
scope "/", MyAppWeb do
# ...
ash_authentication_live_session :authentication_required,
on_mount: {MyAppWeb.LiveUserAuth, :live_user_required} do
live "/protected_route", ProjectLive.Index, :index
end
ash_authentication_live_session :authentication_optional,
on_mount: {MyAppWeb.LiveUserAuth, :live_user_optional} do
live "/", ProjectLive.Index, :index
end
end
# ...
```
--------------------------------
### Create TOTP Setup LiveView Page
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp-2fa.md
Implement a LiveView page for users to set up Two-Factor Authentication (TOTP). This involves defining the `mount` function to fetch the TOTP strategy and rendering a `SetupForm` component. Ensure the `AshAuthentication.Phoenix.Components.Totp.SetupForm` module is aliased.
```elixir
# lib/my_app_web/live/totp_setup_live.ex
defmodule MyAppWeb.TotpSetupLive do
use MyAppWeb, :live_view
alias AshAuthentication.Phoenix.Components.Totp.SetupForm
def mount(_params, _session, socket) do
{:ok, strategy} = AshAuthentication.Info.strategy(MyApp.Accounts.User, :totp)
{:ok, assign(socket, strategy: strategy)}
end
def render(assigns) do
~H"""
Set Up Two-Factor Authentication
<.live_component
module={SetupForm}
id="totp-setup"
strategy={@strategy}
current_user={@current_user}
/>
"""
end
end
```
--------------------------------
### TOTP Authentication Components
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/ui-overrides.md
Configuration parameters for TOTP setup and verification LiveView pages and components.
```APIDOC
## AshAuthentication.Phoenix.TotpSetupLive
### Description
A generic, white-label TOTP setup page for configuring two-factor authentication.
### Parameters
#### Attributes
- **error_class** (string) - Optional - CSS class for the error message when user is not authenticated.
- **root_class** (string) - Optional - CSS class for the root div element.
- **totp_setup_id** (string) - Optional - Element ID for the TotpSetup LiveComponent.
## AshAuthentication.Phoenix.TotpVerifyLive
### Description
A generic, white-label TOTP verification page for two-factor authentication.
### Parameters
#### Attributes
- **root_class** (string) - Optional - CSS class for the root div element.
- **totp_verify_id** (string) - Optional - Element ID for the TotpVerify LiveComponent.
## AshAuthentication.Phoenix.Components.Totp.Verify2faForm
### Description
Generates a verification form for TOTP two-factor authentication.
### Parameters
#### Attributes
- **button_text** (string) - Optional - Text for the submit button.
- **disable_button_text** (string) - Optional - Text for the submit button when the request is happening.
- **error_class** (string) - Optional - CSS class for error messages.
- **form_class** (string) - Optional - CSS class for the form element.
- **instructions_class** (string) - Optional - CSS class for instructions text.
- **instructions_text** (string) - Optional - Instructions text shown above the code input.
- **label_class** (string) - Optional - CSS class for the h2 element.
- **label_text** (string) - Optional - Text for the form heading.
- **recovery_code_link_class** (string) - Optional - CSS class for the recovery code link.
- **recovery_code_link_path** (string) - Optional - Path to the recovery code verification page.
- **recovery_code_link_text** (string) - Optional - Text for the link to recovery code verification.
- **root_class** (string) - Optional - CSS class for the root div element.
- **sign_in_link_class** (string) - Optional - CSS class for the sign-in link when not authenticated.
- **sign_in_link_text** (string) - Optional - Text for the sign-in link.
- **slot_class** (string) - Optional - CSS class for the div surrounding the slot.
```
--------------------------------
### Implement LiveView Authentication Callbacks
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Define `on_mount` callbacks in a LiveView module to handle user authentication logic. This example shows how to manage optional and required authentication states, redirecting users when necessary.
```elixir
defmodule MyAppWeb.LiveUserAuth do
import Phoenix.Component
use MyAppWeb, :verified_routes
def on_mount(:live_user_optional, _params, _session, socket) do
if socket.assigns[:current_user] do
{:cont, socket}
else
{:cont, assign(socket, :current_user, nil)}
end
end
def on_mount(:live_user_required, _params, _session, socket) do
if socket.assigns[:current_user] do
{:cont, socket}
else
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/sign-in")}
end
end
def on_mount(:live_no_user, _params, _session, socket) do
if socket.assigns[:current_user] do
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/")}
else
{:cont, assign(socket, :current_user, nil)}
end
end
end
```
--------------------------------
### Use Role-Based Access in LiveView
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/liveview.md
Apply role-based access control within a LiveView's `on_mount` callback. This example demonstrates how to specify required roles for accessing a LiveView.
```elixir
on_mount {MyAppWeb.LiveUserAuth, {:required_role: :admin}}
```
```elixir
on_mount {MyAppWeb.LiveUserAuth, {:required_roles: [:admin, :staff]}}
```
--------------------------------
### Define TOTP Routes in Phoenix Router
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp-2fa.md
Use the totp_2fa_route and totp_setup_route macros to expose verification and setup pages. The set_actor plug is required in the browser pipeline for these routes to function.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {MyAppWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :load_from_session
plug :set_actor, :user
end
scope "/", MyAppWeb do
pipe_through :browser
# Standard auth routes
auth_routes AuthController, MyApp.Accounts.User, path: "/auth"
# TOTP verification route - defaults to /totp-verify
totp_2fa_route MyApp.Accounts.User, :totp, auth_routes_prefix: "/auth"
# TOTP setup route - defaults to /totp-setup
totp_setup_route MyApp.Accounts.User, :totp, auth_routes_prefix: "/auth"
end
end
```
--------------------------------
### Redirect to Recovery Codes After TOTP Setup
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/recovery-codes.md
Implement a success clause in the auth controller to redirect users to the recovery codes page after completing TOTP setup.
```elixir
# Added automatically by the igniter
def success(conn, {_, :confirm_setup}, user, token) do
conn
|> store_in_session(user)
|> set_live_socket_id(token)
|> assign(:current_user, user)
|> redirect(to: ~p"/recovery-codes")
end
```
--------------------------------
### Configure Recovery Code Plug
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/recovery-codes.md
Use this plug in controller pipelines to enforce recovery code setup for users.
```elixir
pipeline :require_recovery_codes do
plug AshAuthentication.Phoenix.Plug.RequireRecoveryCodes,
resource: MyApp.Accounts.User,
on_missing: :redirect_to_setup,
setup_path: "/recovery-codes"
end
```
--------------------------------
### Password Strategy Metadata Structure
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/topics/authentication-metadata.md
Example of the metadata map generated when using the password authentication strategy.
```elixir
%{
authentication_strategies: [:password],
token: "..."
}
```
--------------------------------
### TOTP Strategy Metadata Structure
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/topics/authentication-metadata.md
Example of the metadata map generated when using the TOTP authentication strategy.
```elixir
%{
authentication_strategies: [:totp],
totp_verified_at: ~U[2024-01-15 10:30:00Z],
token: "..."
}
```
--------------------------------
### Implement Authentication Callbacks with AshAuthentication.Phoenix.Controller
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Define success and failure callbacks to handle authentication outcomes. This example shows a controller-backed flow redirecting to a return path or sign-in page.
```elixir
defmodule MyAppWeb.AuthController do
use MyAppWeb, :controller
use AshAuthentication.Phoenix.Controller
def success(conn, _activity, user, token) do
return_to = get_session(conn, :return_to) || ~p"/"
conn
|> delete_session(:return_to)
|> store_in_session(user)
|> assign(:current_user, user)
|> set_live_socket_id(token)
|> redirect(to: return_to)
end
def failure(conn, _activity, _reason) do
conn
|> put_flash(:error, "Incorrect email or password")
|> redirect(to: ~p"/sign-in")
end
def sign_out(conn, _params) do
return_to = get_session(conn, :return_to) || ~p"/"
conn
|> clear_session(:my_app)
|> redirect(to: return_to)
end
end
```
--------------------------------
### GET /recovery-code-verify/:token or /recovery-code-verify
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/recovery-codes.md
Generates a recovery code verification page. Supports token-based verification for 2FA fallback after password sign-in, or step-up verification for already-authenticated users.
```APIDOC
## GET /recovery-code-verify/:token or /recovery-code-verify
### Description
Generates a recovery code verification page. Supports two modes: Token-based (used after password sign-in as a 2FA fallback) and Step-up (used when an already-authenticated user needs to re-verify their identity).
### Method
GET
### Endpoint
/recovery-code-verify/:token or /recovery-code-verify
### Parameters
#### Path Parameters
- **token** (string) - Optional - Used in token-based mode after password sign-in.
```
--------------------------------
### Customize Authentication UI Components
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Use the `AshAuthentication.Phoenix.Overrides` module to customize CSS classes, text, and image URLs for authentication components. This example overrides banner and password form elements.
```elixir
defmodule MyAppWeb.AuthOverrides do
use AshAuthentication.Phoenix.Overrides
alias AshAuthentication.Phoenix.Components
# Customize the banner image
override Components.Banner do
set :image_url, "/images/my-logo.png"
set :dark_image_url, "/images/my-logo-dark.png"
set :href_url, "/"
end
# Customize password form appearance
override Components.Password do
set :sign_in_toggle_text, "Already have an account? Sign in"
set :register_toggle_text, "Don't have an account? Register"
set :reset_toggle_text, "Forgot password?"
end
# Customize input styling
override Components.Password.Input do
set :input_class, "w-full px-4 py-2 border rounded-lg focus:ring-2"
set :label_class, "block text-sm font-medium mb-1"
set :submit_class, "w-full bg-blue-600 text-white py-2 rounded-lg"
set :identity_input_label, "Email Address"
set :password_input_label, "Your Password"
end
# Customize sign-in form text
override Components.Password.SignInForm do
set :button_text, "Log In"
set :disable_button_text, "Logging in..."
end
end
```
--------------------------------
### Configure Router for TOTP
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp.md
Use standard authentication route macros to enable TOTP sign-in.
```elixir
scope "/", MyAppWeb do
pipe_through :browser
auth_routes AuthController, MyApp.Accounts.User, path: "/auth"
sign_in_route(auth_routes_prefix: "/auth")
end
```
--------------------------------
### GET /recovery-codes
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/recovery-codes.md
Generates a page for generating and displaying recovery codes. This route should be protected by authentication middleware.
```APIDOC
## GET /recovery-codes
### Description
Generates a page for generating and displaying recovery codes. This should be placed behind authentication middleware so only authenticated users can access it.
### Method
GET
### Endpoint
/recovery-codes
```
--------------------------------
### Load Authenticated Users with Plugs
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Use plug helpers to load users from sessions or bearer tokens, and to store users in the session. These plugs are typically configured in your router pipelines.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
# Load user from session token
plug :load_from_session
# Optionally sign in with remember me cookie
plug :sign_in_with_remember_me
end
pipeline :api do
plug :accepts, ["json"]
# Load user from Authorization header bearer token
plug :load_from_bearer
# Set the Ash actor for authorization
plug :set_actor, :user
end
# In a controller or plug, store user in session:
# conn |> store_in_session(user)
# Revoke tokens on sign out:
# conn |> revoke_bearer_tokens()
# conn |> revoke_session_tokens()
end
```
--------------------------------
### Configure LiveView Routes with AshAuthentication
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Use the `ash_authentication_live_session` macro in your router to define routes that require authentication or where authentication is optional. The `on_mount` option specifies how to handle user authentication status.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
scope "/", MyAppWeb do
pipe_through :browser
# Routes requiring authentication
ash_authentication_live_session :authenticated,
on_mount: {MyAppWeb.LiveUserAuth, :live_user_required} do
live "/dashboard", DashboardLive, :index
live "/settings", SettingsLive, :index
end
# Routes where auth is optional
ash_authentication_live_session :public,
on_mount: {MyAppWeb.LiveUserAuth, :live_user_optional} do
live "/", HomeLive, :index
end
end
end
```
--------------------------------
### Implement 2FA Grace Period in Phoenix LiveView
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp-2fa.md
Use this module to allow users a grace period to set up 2FA. It checks if 2FA is configured or if the grace period is still active before proceeding.
```elixir
defmodule MyAppWeb.Require2FAWithGrace do
import Phoenix.Component
import Phoenix.LiveView
alias AshAuthentication.Phoenix.TotpHelpers
@grace_period_days 7
def on_mount(:require_2fa_with_grace, _params, _session, socket) do
user = socket.assigns[:current_user]
cond do
is_nil(user) ->
{:halt, redirect(socket, to: "/sign-in")}
TotpHelpers.totp_configured?(user) ->
{:cont, assign(socket, :totp_configured, true)}
within_grace_period?(user) ->
socket =
socket
|> assign(:totp_configured, false)
|> assign(:grace_period_remaining, days_remaining(user))
|> put_flash(:warning, "Please set up 2FA within #{days_remaining(user)} days")
{:cont, socket}
true ->
socket =
socket
|> put_flash(:error, "Two-factor authentication is now required")
|> redirect(to: "/auth/totp/setup")
{:halt, socket}
end
end
defp within_grace_period?(user) do
days_remaining(user) > 0
end
defp days_remaining(user) do
created = user.inserted_at
deadline = DateTime.add(created, @grace_period_days, :day)
DateTime.diff(deadline, DateTime.utc_now(), :day) |> max(0)
end
end
```
--------------------------------
### Implement AuthController for Authentication Callbacks
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/get-started.md
Create a controller to handle success, failure, and sign-out actions for authentication flows.
```elixir
defmodule ExampleWeb.AuthController do
use ExampleWeb, :controller
use AshAuthentication.Phoenix.Controller
def success(conn, _activity, user, _token) do
return_to = get_session(conn, :return_to) || ~p"/"
conn
|> delete_session(:return_to)
|> store_in_session(user)
# If your resource has a different name, update the assign name here (i.e :current_admin)
|> assign(:current_user, user)
|> redirect(to: return_to)
end
def failure(conn, _activity, _reason) do
conn
|> put_flash(:error, "Incorrect email or password")
|> redirect(to: ~p"/sign-in")
end
def sign_out(conn, _params) do
return_to = get_session(conn, :return_to) || ~p"/"
conn
|> clear_session(:my_app)
|> redirect(to: return_to)
end
end
```
--------------------------------
### Multi-Factor Authentication Metadata Accumulation
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/topics/authentication-metadata.md
Example of the metadata map showing accumulated strategies after both password and TOTP verification.
```elixir
# After password + TOTP verification
%{
authentication_strategies: [:password, :totp],
totp_verified_at: ~U[2024-01-15 10:30:00Z],
token: "..."
}
```
--------------------------------
### Generated Auth Controller Clauses for 2FA
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp-2fa.md
These clauses handle the 2FA flow during sign-in and registration. They check TOTP configuration and redirect users to the appropriate setup or verification pages.
```elixir
defmodule MyAppWeb.AuthController do
use MyAppWeb, :controller
use AshAuthentication.Phoenix.Controller
# Sign-in interception: check if TOTP is configured
def success(conn, {_, phase} = _activity, user, token)
when phase in [:sign_in, :sign_in_with_token] do
return_to = get_session(conn, :return_to) || ~p"/"
if AshAuthentication.Phoenix.TotpHelpers.totp_configured?(user) do
# TOTP is set up — store user in session and redirect to verify
conn
|> store_in_session(user)
|> set_live_socket_id(token)
|> assign(:current_user, user)
|> put_session(:return_to, return_to)
|> redirect(to: ~p"/totp-verify/#{token}")
else
# No TOTP configured — redirect to setup
conn
|> store_in_session(user)
|> set_live_socket_id(token)
|> assign(:current_user, user)
|> put_session(:return_to, return_to)
|> redirect(to: ~p"/totp-setup")
end
end
# Registration: always redirect to TOTP setup
def success(conn, {_, :register}, user, token) do
return_to = get_session(conn, :return_to) || ~p"/"
conn
|> store_in_session(user)
|> set_live_socket_id(token)
|> assign(:current_user, user)
|> put_session(:return_to, return_to)
|> redirect(to: ~p"/totp-setup")
end
# Default catch-all for other auth activities
def success(conn, activity, user, token) do
# ... standard success handling
end
# ...
end
```
--------------------------------
### RequireTotp LiveView Hook Configuration
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp-2fa.md
Use the RequireTotp on_mount hook for LiveView routes to enforce 2FA. Configure options like setup_path and current_user_assign as a tuple.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
import AshAuthentication.Phoenix.LiveSession.RequireTotp
scope "/", MyAppWeb do
pipe_through :browser
ash_authentication_live_session :protected,
on_mount: [{AshAuthentication.Phoenix.LiveSession.RequireTotp, :require_totp}] do
live "/dashboard", DashboardLive
live "/settings", SettingsLive
end
end
end
```
```elixir
on_mount: [{AshAuthentication.Phoenix.LiveSession.RequireTotp,
{:require_totp,
setup_path: "/setup-2fa",
current_user_assign: :actor
}}]
```
--------------------------------
### Define UI Overrides Module
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/ui-overrides.md
Create a module that uses `AshAuthentication.Phoenix.Overrides` to define custom properties for UI components. This example shows how to override image URLs for the Banner component.
```elixir
defmodule MyAppWeb.AuthOverrides do
use AshAuthentication.Phoenix.Overrides
# Override a property per component
override AshAuthentication.Phoenix.Components.Banner do
# include any number of properties you want to override
set :image_url, "/images/rickroll.gif"
set :dark_image_url, "/images/rickroll-dark.gif"
end
end
```
--------------------------------
### Configure Gettext for Internationalization
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Integrate Gettext for translating authentication UI text. Copy translation templates and ensure the backend is correctly configured in the router.
```elixir
# In your router
scope "/", MyAppWeb do
sign_in_route(
overrides: [MyAppWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default],
gettext_backend: {MyAppWeb.Gettext, "auth"},
auth_routes_prefix: "/auth"
)
end
# Copy translation templates from the package:
# cp -rv deps/ash_authentication_phoenix/i18n/gettext/* priv/gettext
# The package includes translations for multiple languages
# including German (de) and Swedish (sv)
```
--------------------------------
### Configure Confirmation Route
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Set up the route for email confirmation, used to verify user email addresses. This is typically used when require_interaction? is true.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
scope "/", MyAppWeb do
pipe_through :browser
# Confirmation page (when require_interaction? is true)
confirm_route MyApp.Accounts.User, :confirm,
path: "/confirm",
auth_routes_prefix: "/auth"
end
end
```
--------------------------------
### Implement Email Delivery Logic
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/get-started.md
Handles the construction and delivery of password reset emails using Swoosh.
```elixir
defmodule Example.Accounts.Emails do
@moduledoc """
Delivers emails.
"""
import Swoosh.Email
def deliver_reset_password_instructions(user, url) do
if !url do
raise "Cannot deliver reset instructions without a url"
end
deliver(user.email, "Reset Your Password", """
Hi #{user.email},
Click here to reset your password.
If you didn't request this change, please ignore this.
")
end
# For simplicity, this module simply logs messages to the terminal.
# You should replace it by a proper email or notification tool, such as:
#
# * Swoosh - https://hexdocs.pm/swoosh
# * Bamboo - https://hexdocs.pm/bamboo
#
defp deliver(to, subject, body) do
IO.puts("Sending email to #{to} with subject #{subject} and body #{body}")
new()
|> from({"Zach", "zach@ash-hq.org"}) # TODO: Replace with your email
|> to(to_string(to))
|> subject(subject)
|> put_provider_option(:track_links, "None")
|> html_body(body)
|> Example.Mailer.deliver!()
end
end
```
--------------------------------
### Configure Router with Overrides and Gettext
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/ui-overrides.md
Modify your router to include the custom overrides module and specify the Gettext backend for internationalization. Ensure the default overrides are listed last.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
# ...
scope "/", MyAppWeb do
sign_in_route overrides: [MyAppWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default],
gettext_backend: {MyAppWeb.Gettext, "auth"}
end
end
```
--------------------------------
### Implement Role-Based Access Control
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/liveview.md
Add `on_mount` hooks to check user roles for access control. These functions verify if the current user has the required role before allowing access to a LiveView.
```elixir
def on_mount({:required_role, role}, _params, _session, socket) do
if socket.assigns[:current_user] && socket.assigns[:current_user].role == role do
{:cont, socket}
else
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/")}
end
end
```
```elixir
def on_mount({:required_roles, roles}, _params, _session, socket) do
if socket.assigns[:current_user] && Enum.any?(roles, &(socket.assigns[:current_user].role == &1)) do
{:cont, socket}
else
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/")}
end
end
```
--------------------------------
### Update Formatter Configuration
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/get-started.md
Include ash_authentication_phoenix in the formatter dependencies.
```elixir
[
import_deps: [
:ash_authentication_phoenix, # <-------- Add this line
:ash_authentication,
:ash_postgres,
:ash,
:ecto,
:ecto_sql,
:phoenix
],
subdirectories: ["priv/*/migrations"],
plugins: [Spark.Formatter, Phoenix.LiveView.HTMLFormatter],
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
]
```
--------------------------------
### Displaying Metadata in Templates
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/topics/authentication-metadata.md
Render authentication information in a HEEx template.
```heex
Current Session
Authenticated with:
<%= Enum.map_join(@auth_strategies, ", ", &to_string/1) %>
<%= if @totp_verified_at do %>
TOTP verified at: <%= Calendar.strftime(@totp_verified_at, "%Y-%m-%d %H:%M UTC") %>
<% end %>
```
--------------------------------
### Wrap Live Routes with Live Session
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/liveview.md
Wrap your LiveView routes with `ash_authentication_live_session` to automatically set user assigns. This provides a basic session wrapper.
```elixir
ash_authentication_live_session :session_name do
live "/route", ProjectLive.Index, :index
end
```
--------------------------------
### Check TOTP Status with TotpHelpers
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp-2fa.md
Use the TotpHelpers module to check if a user has TOTP configured, if a resource supports TOTP, or to retrieve the TOTP strategy. Ensure the `AshAuthentication.Phoenix.TotpHelpers` module is aliased.
```elixir
alias AshAuthentication.Phoenix.TotpHelpers
# Check if user has TOTP configured
TotpHelpers.totp_configured?(user)
#=> true
# Check if resource supports TOTP
TotpHelpers.totp_available?(MyApp.Accounts.User)
#=> true
# Get the TOTP strategy
{:ok, strategy} = TotpHelpers.get_totp_strategy(MyApp.Accounts.User)
```
--------------------------------
### Configure Magic Link Authentication Route
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Set up the route for magic link (passwordless) sign-in. This is typically used when require_interaction? is true.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
scope "/", MyAppWeb do
pipe_through :browser
# Magic link sign-in page (when require_interaction? is true)
magic_sign_in_route MyApp.Accounts.User, :magic_link,
path: "/magic-link",
auth_routes_prefix: "/auth"
end
end
```
--------------------------------
### Logging Authentication Events
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/topics/authentication-metadata.md
Create an audit log entry using authentication metadata.
```elixir
defmodule MyApp.AuthAudit do
def log_authentication(user, conn) do
MyApp.AuditLog.create!(%{
user_id: user.id,
strategies: user.__metadata__[:authentication_strategies] || [],
totp_verified: user.__metadata__[:totp_verified_at] != nil,
ip_address: get_ip(conn),
user_agent: get_user_agent(conn),
timestamp: DateTime.utc_now()
})
end
defp get_ip(conn) do
conn.remote_ip |> :inet.ntoa() |> to_string()
end
defp get_user_agent(conn) do
Plug.Conn.get_req_header(conn, "user-agent") |> List.first()
end
end
```
--------------------------------
### Implement Email Notifier
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/password-change.md
Create a notifier module to trigger email delivery on password change.
```elixir
defmodule MyApp.Notifiers.EmailNotifier do
use Ash.Notifier
alias MyApp.Accounts.User
@impl true
def notify(%Ash.Notifier.Notification{action: %{name: :change_password}, data: user}) do
User.Email.deliver_password_change_notification(user)
end
end
```
--------------------------------
### Define LiveUserAuth on_mount Hooks
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/liveview.md
Implement `on_mount` hooks in `MyAppWeb.LiveUserAuth` for different authentication behaviors: optional user, required user, and no user required. These hooks manage user session state and redirects.
```elixir
# lib/my_app_web/live_user_auth.ex
defmodule MyAppWeb.LiveUserAuth do
@moduledoc """
Helpers for authenticating users in LiveViews.
"""
import Phoenix.Component
use MyAppWeb, :verified_routes
def on_mount(:live_user_optional, _params, _session, socket) do
if socket.assigns[:current_user] do
{:cont, socket}
else
{:cont, assign(socket, :current_user, nil)}
end
end
def on_mount(:live_user_required, _params, _session, socket) do
if socket.assigns[:current_user] do
{:cont, socket}
else
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/sign-in")}
end
end
def on_mount(:live_no_user, _params, _session, socket) do
if socket.assigns[:current_user] do
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/")}
else
{:cont, assign(socket, :current_user, nil)}
end
end
end
```
--------------------------------
### Define Authentication Routes with AshAuthentication.Phoenix.Router
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Use router macros to generate routes for authentication flows. Import `AshAuthentication.Phoenix.Router` in your router file to access these helpers.
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
use AshAuthentication.Phoenix.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, {MyAppWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :load_from_session
end
pipeline :api do
plug :accepts, ["json"]
plug :load_from_bearer
plug :set_actor, :user
end
scope "/", MyAppWeb do
pipe_through :browser
# Controller-backed authentication routes
auth_routes AuthController, MyApp.Accounts.User, path: "/auth"
# Sign out with CSRF protection (GET shows confirmation, DELETE signs out)
sign_out_route AuthController
# LiveView sign-in page with registration and reset toggles
sign_in_route(
register_path: "/register",
reset_path: "/reset",
auth_routes_prefix: "/auth"
)
# Password reset page (accessed via token in email)
reset_route auth_routes_prefix: "/auth"
end
end
```
--------------------------------
### Use DaisyUI Theme Support
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Apply DaisyUI-specific overrides for styling instead of the default TailwindCSS theme. Configure this in your router.
```elixir
# In your router
scope "/", MyAppWeb do
sign_in_route(
register_path: "/register",
reset_path: "/reset",
auth_routes_prefix: "/auth",
overrides: [AshAuthentication.Phoenix.Overrides.DaisyUI]
)
end
# In your app.css for dark theme support:
# @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
```
--------------------------------
### Configure Phoenix Router for Ash Authentication
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/get-started.md
Add authentication routes and plugs to the Phoenix router module.
```elixir
defmodule ExampleWeb.Router do
use ExampleWeb, :router
# add these lines -->
use AshAuthentication.Phoenix.Router
import AshAuthentication.Plug.Helpers
# <-- add these lines
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, {ExampleWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :load_from_session # <-------- Add this line
end
pipeline :api do
plug :accepts, ["json"]
# add these lines -->
plug :load_from_bearer
plug :set_actor, :user
# <-- add these lines
end
scope "/", ExampleWeb do
pipe_through :browser
get "/", PageController, :home
# add these lines -->
# Standard controller-backed routes
auth_routes AuthController, Example.Accounts.User, path: "/auth"
sign_out_route AuthController
# Prebuilt LiveViews for signing in, registration, resetting, etc.
# Leave out `register_path` and `reset_path` if you don't want to support
# user registration and/or password resets respectively.
sign_in_route(register_path: "/register", reset_path: "/reset", auth_routes_prefix: "/auth")
reset_route [auth_routes_prefix: "/auth"]
# <-- add these lines
end
...
end
```
--------------------------------
### OAuth2 Components
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/ui-overrides.md
Configuration parameters for Apple and general OAuth2 sign-in button components.
```APIDOC
## AshAuthentication.Phoenix.Components.Apple / OAuth2
### Description
Generates sign-in buttons for Apple or generic OAuth2 strategies.
### Parameters
- **icon_class** (string) - CSS classes for the icon SVG.
- **link_class** (string) - CSS classes for the a element.
- **root_class** (string) - CSS classes for the root div element.
- **icon_src** (map) - (OAuth2 only) Map of strategy names to icon sources.
```
--------------------------------
### Accessing Authentication Strategies
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/topics/authentication-metadata.md
Retrieve the list of authentication strategies used in the current session from the user metadata.
```elixir
user.__metadata__.authentication_strategies
#=> [:password]
# Or for TOTP
#=> [:totp]
```
--------------------------------
### Preserve Metadata via Session Storage
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/topics/authentication-metadata.md
Demonstrates how to extract metadata from the user struct into a Phoenix session and restore it to the user struct using a plug.
```elixir
# In your auth controller callback
def callback(conn, _params) do
user = conn.assigns.subject
conn
|> put_session(:auth_strategies, user.__metadata__[:authentication_strategies])
|> put_session(:totp_verified_at, user.__metadata__[:totp_verified_at])
|> redirect(to: "/")
end
# In a plug to restore metadata
def restore_auth_metadata(conn, _opts) do
if user = conn.assigns[:current_user] do
user =
user
|> Ash.Resource.put_metadata(:authentication_strategies, get_session(conn, :auth_strategies))
|> Ash.Resource.put_metadata(:totp_verified_at, get_session(conn, :totp_verified_at))
assign(conn, :current_user, user)
else
conn
end
end
```
--------------------------------
### Customize Authentication Routes
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/get-started.md
Specify custom layouts and prefixes for authentication routes using route helper options.
```elixir
reset_route(layout: {MyAppWeb, :live}, auth_routes_prefix: "/auth")
```
--------------------------------
### API Authentication Controller with JSON Responses
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Implement API authentication callbacks to return JSON responses, including bearer tokens for successful authentication.
```elixir
defmodule MyAppWeb.ApiAuthController do
use MyAppWeb, :controller
use AshAuthentication.Phoenix.Controller
def success(conn, _activity, _user, token) do
conn
|> put_status(200)
|> json(%{
authentication: %{
status: :success,
bearer: token
}
})
end
def failure(conn, _activity, _reason) do
conn
|> put_status(401)
|> json(%{
authentication: %{
status: :failed
}
})
end
def sign_out(conn, _params) do
conn
|> revoke_bearer_tokens()
|> json(%{status: :ok})
end
end
```
--------------------------------
### Apply Authentication Overrides in Router
Source: https://context7.com/team-alembic/ash_authentication_phoenix/llms.txt
Apply custom authentication overrides by including your override module in the `overrides` list when defining sign-in routes. This ensures your customizations are used across authentication flows.
```elixir
scope "/", MyAppWeb do
sign_in_route(
overrides: [MyAppWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default],
auth_routes_prefix: "/auth"
)
end
```
--------------------------------
### Configure LiveView Hook
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/recovery-codes.md
Add the RequireRecoveryCodes hook to your live_session to protect LiveView routes.
```elixir
live_session :require_recovery_codes,
on_mount: [
{AshAuthentication.Phoenix.LiveSession, :default},
{AshAuthentication.Phoenix.LiveSession.RequireRecoveryCodes, :require_recovery_codes}
] do
live "/secure", SecureLive
end
```
--------------------------------
### Configure TOTP in User Resource
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/totp.md
Define the TOTP strategy and required attributes within the Ash resource.
```elixir
defmodule MyApp.Accounts.User do
use Ash.Resource,
extensions: [AshAuthentication],
domain: MyApp.Accounts
authentication do
tokens do
enabled? true
token_resource MyApp.Accounts.Token
signing_secret MyApp.Secrets
end
strategies do
totp do
identity_field :email
issuer "MyApp"
sign_in_enabled? true
# Optional: require confirmation before storing secret
confirm_setup_enabled? true
end
end
end
attributes do
uuid_primary_key :id
attribute :email, :ci_string, allow_nil?: false
attribute :totp_secret, :binary, allow_nil?: true, sensitive?: true
attribute :last_totp_at, :datetime, allow_nil?: true, sensitive?: true
end
identities do
identity :unique_email, [:email]
end
end
```
--------------------------------
### Magic Link Components
Source: https://github.com/team-alembic/ash_authentication_phoenix/blob/main/documentation/tutorials/ui-overrides.md
Components for handling magic link sign-in functionality.
```APIDOC
## AshAuthentication.Phoenix.MagicSignInLive
### Description
A generic, white-label confirmation page.
### Parameters
#### Query Parameters
- **:magic_sign_in_id** (string) - Optional - Element ID for the `MagicSignIn` LiveComponent.
- **:root_class** (string) - Optional - CSS class for the root `div` element.
```
```APIDOC
## AshAuthentication.Phoenix.Components.MagicLink
### Description
Generates a sign-in form for a resource using the "Magic link" strategy.
### Parameters
#### Query Parameters
- **:checkbox_class** (string) - Optional - CSS class for the `remember_me` checkbox.
- **:checkbox_label_class** (string) - Optional - CSS class for the `remember_me` check box label.
- **:disable_button_text** (string) - Optional - Text for the submit button when the request is happening.
- **:form_class** (string) - Optional - CSS class for the `form` element.
- **:label_class** (string) - Optional - CSS class for the `h2` element.
- **:remember_me_class** (string) - Optional - CSS class for the `div` element surrounding the remember me field.
- **:request_flash_text** (string) - Optional - Text for the flash message when a request is received. Set to `nil` to disable.
- **:root_class** (string) - Optional - CSS class for the root `div` element.
```
```APIDOC
## AshAuthentication.Phoenix.Components.MagicLink.SignIn
### Description
Renders a magic sign in button.
### Parameters
#### Query Parameters
- **:root_class** (string) - Optional - CSS class for the root `div` element.
- **:show_banner** (boolean) - Optional - Whether or not to show the banner.
- **:strategy_class** (string) - Optional - CSS class for the `div` surrounding each strategy component.
```
```APIDOC
## AshAuthentication.Phoenix.Components.MagicLink.Form
### Description
Generates a default magic sign in form.
### Parameters
#### Query Parameters
- **:disable_button_text** (string) - Optional - Text for the submit button when the request is happening.
- **:form_class** (string) - Optional - CSS class for the `form` element.
- **:label_class** (string) - Optional - CSS class for the `h2` element.
- **:root_class** (string) - Optional - CSS class for root `div` element.
```