### Install Ash Authentication Separately Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Installs only the `ash_authentication` package first, then installs `ash_authentication_phoenix`. This is useful to see the specific changes introduced by `ash_authentication_phoenix`. ```bash mix igniter.install ash_authentication mix igniter.install ash_authentication_phoenix ``` -------------------------------- ### Install Ash Authentication Phoenix Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Installs the `ash_authentication_phoenix` package. If `ash_authentication` is not already installed, this command will also install it. ```bash mix igniter.install ash_authentication_phoenix ``` -------------------------------- ### Install Ash Authentication Extension (CLI) Source: https://hexdocs.pm/ash_authentication/get-started Installs the core ash_authentication extension and optionally the phoenix extension using the Mix Igniter tool. This command allows specifying authentication strategies like magic_link and password during installation. ```bash mix igniter.install ash_authentication --auth-strategy magic_link,password ``` ```bash mix igniter.install ash_authentication_phoenix --auth-strategy magic_link,password ``` -------------------------------- ### Phoenix Router Setup with Ash Authentication Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Configures the Phoenix router to include authentication routes and pipelines using helper macros provided by `ash_authentication_phoenix`. This involves adding specific `use` and `plug` statements, and defining authentication-related routes. ```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 ``` -------------------------------- ### Start Phoenix Server Command Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started This command starts the Phoenix server, allowing you to access your application at `localhost:4000`. Ensure your application is properly configured before running this command. ```bash mix phx.server ``` -------------------------------- ### Update Formatter Configuration for Ash Authentication Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Adds `ash_authentication_phoenix` and related dependencies to the `.formatter.exs` file to enable auto-formatting for the project. ```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"] ] ``` -------------------------------- ### Customizing OAuth2 Registration Action Source: https://hexdocs.pm/ash_authentication/get-started Example of customizing the 'register' action for the OAuth2 strategy (GitHub example). It includes required changes and logic to extract user data from the OAuth response. ```elixir # OAuth2 registration create :register_with_github do argument :user_info, :map, allow_nil?: false argument :oauth_tokens, :map, allow_nil?: false, sensitive?: true # Required for OAuth2: change AshAuthentication.GenerateTokenChange change AshAuthentication.Strategy.OAuth2.IdentityChange # Extract user data from OAuth response: change fn changeset, _ctx -> user_info = Ash.Changeset.get_argument(changeset, :user_info) Ash.Changeset.change_attributes(changeset, Map.take(user_info, ["email", "name"])) end end ``` -------------------------------- ### Customizing Password Registration Action Source: https://hexdocs.pm/ash_authentication/get-started Example of customizing the 'register' action for the password strategy. It includes required changes like generating a token and hashing the password. ```elixir # Password registration create :register_with_password do # Your custom arguments and logic... # Required for password strategy: change AshAuthentication.GenerateTokenChange change AshAuthentication.Strategy.Password.HashPasswordChange end ``` -------------------------------- ### Setup Ash Authentication Token Resource (Elixir) Source: https://hexdocs.pm/ash_authentication/get-started Defines the `Token` resource for Ash Authentication, specifying `AshPostgres.DataLayer`, the `AshAuthentication.TokenResource` extension, and policy configurations. It also sets up the associated PostgreSQL table and repository. ```elixir # lib/my_app/accounts/token.ex defmodule MyApp.Accounts.Token do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication.TokenResource], # If using policies, enable the policy authorizer: authorizers: [Ash.Policy.Authorizer], domain: MyApp.Accounts postgres do table "tokens" repo MyApp.Repo end policies do bypass AshAuthentication.Checks.AshAuthenticationInteraction do authorize_if always() end end end ``` -------------------------------- ### Add Example Repo for Multi-Tenant Enabled User Source: https://hexdocs.pm/ash_authentication/changelog This improvement provides an example repository demonstrating how to enable and use multi-tenancy with user authentication. This serves as a helpful guide for developers implementing multitenant features. ```elixir adding example repo for multi tenant enabled user ``` -------------------------------- ### Customize Route Helpers in Phoenix Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Demonstrates how to customize route helpers in Phoenix to integrate AshAuthentication with existing layouts and specify custom route prefixes. This is useful when migrating an existing application. ```elixir reset_route(layout: {MyAppWeb, :live}, auth_routes_prefix: "/auth") ``` -------------------------------- ### Ash Authentication Controller Implementation Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Defines the `AuthController` for handling authentication callbacks, including successful sign-ins and failures. It uses `AshAuthentication.Phoenix.Controller` to manage session and redirects. ```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 ``` -------------------------------- ### Ash Authentication Plug Setup Source: https://hexdocs.pm/ash_authentication/get-started Defines an authentication plug for Phoenix or Plug applications using AshAuthentication.Plug. It handles successful and failed authentication attempts, differentiating between API requests and traditional web responses. ```elixir # lib/my_app/auth_plug.ex defmodule MyApp.AuthPlug do use AshAuthentication.Plug, otp_app: :my_app def handle_success(conn, _activity, user, token) do if is_api_request?(conn) do conn |> send_resp(200, Jason.encode!(%{ authentication: %{ success: true, token: token } })) else conn |> store_in_session(user) |> send_resp(200, EEx.eval_string("""

Welcome back <%= @user.email %>

""", user: user)) end end def handle_failure(conn, _activity, _reason) do if is_api_request?(conn) do conn |> send_resp(401, Jason.encode!(%{ authentication: %{ success: false } })) else conn |> send_resp(401, "

Incorrect email or password

") end end defp is_api_request?(conn), do: "application/json" in get_req_header(conn, "accept") end ``` -------------------------------- ### Elixir Email Delivery and Reset Instructions Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started The `Example.Accounts.Emails` module handles the delivery of emails, specifically the password reset instructions. It includes a `deliver_reset_password_instructions` function that constructs the email content and a private `deliver` function that simulates email sending by logging to the console and using `Example.Mailer.deliver!`. This simulates integration with an email sending library like 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 ``` -------------------------------- ### Add Ash Authentication Dependency (Mix) Source: https://hexdocs.pm/ash_authentication/get-started Adds the ash_authentication Elixir library as a project dependency in the mix.exs file. It also configures the formatter to import the dependency for consistent code formatting. ```elixir # mix.exs defp deps() do [ # ... {:ash_authentication, "~> 4.0"} ] end ``` ```elixir # .formatter.exs [ import_deps: [..., :ash_authentication] ] ``` -------------------------------- ### Configure Tailwind CSS for Ash Authentication Phoenix Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Shows how to modify the `assets/tailwind.config.js` file to include the `ash_authentication_phoenix` dependency. This is necessary for using the default Tailwind-based components without overriding them. ```javascript // See the Tailwind configuration guide for advanced usage // https://tailwindcss.com/docs/configuration const plugin = require("tailwindcss/plugin"); module.exports = { content: [ "./js/**/*.js", "../lib/*_web.ex", "../lib/*_web/**/*.*ex", "../deps/ash_authentication_phoenix/**/*.*ex", // <-- Add this line ], theme: { extend: { colors: { brand: "#FD4F00", }, }, }, plugins: [ require("@tailwindcss/forms"), plugin(({ addVariant }) => addVariant("phx-no-feedback", [ ".phx-no-feedback&", ".phx-no-feedback &", ]) ), plugin(({ addVariant }) => addVariant("phx-click-loading", [ ".phx-click-loading&", ".phx-click-loading &", ]) ), plugin(({ addVariant }) => addVariant("phx-submit-loading", [ ".phx-submit-loading&", ".phx-submit-loading &", ]) ), plugin(({ addVariant }) => addVariant("phx-change-loading", [ ".phx-change-loading&", ".phx-change-loading &", ]) ), ], }; ``` -------------------------------- ### Install Ash Authentication Phoenix Extension Source: https://hexdocs.pm/ash_authentication/4.9.5/get-started Installs the ash_authentication_phoenix extension for Phoenix applications. This command should be used in conjunction with or as an alternative to the base `ash_authentication` installation, also specifying authentication strategies. ```bash mix igniter.install ash_authentication_phoenix --auth-strategy magic_link,password ``` -------------------------------- ### Override Mix Routes Alias for Phoenix <= 1.7 Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Overrides the `phx.routes` alias in `mix.exs` to include routes from `ash_authentication_phoenix`. This is specific to Phoenix versions 1.7 and earlier. ```elixir defp aliases do [ setup: ["deps.get", "ash.setup", "assets.setup", "assets.build", "run priv/repo/seeds.exs"], ... "phx.routes": ["phx.routes", "ash_authentication.phoenix.routes"] # <-------- Add this line ] end ``` -------------------------------- ### Install Ash Authentication Extension Source: https://hexdocs.pm/ash_authentication/4.9.5/get-started Installs the ash_authentication extension with specified authentication strategies (magic_link, password) using the `mix igniter.install` command. This is a prerequisite for using the authentication features. ```bash mix igniter.install ash_authentication --auth-strategy magic_link,password ``` -------------------------------- ### Integrate daisyUI Overrides in Phoenix Router Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Illustrates how to use daisyUI-specific overrides for Ash Authentication in Phoenix. Replace `AshAuthentication.Phoenix.Overrides.Default` with `AshAuthentication.Phoenix.Overrides.DaisyUI` in your router configuration. ```elixir sign_in_route register_path: "/register", reset_path: "/reset", auth_routes_prefix: "/auth", on_mount: [{ExampleWeb.LiveUserAuth, :live_no_user}], overrides: [AshAuthentication.Phoenix.Overrides.DaisyUI] ``` -------------------------------- ### Install Ash Authentication Phoenix Extension Source: https://hexdocs.pm/ash_authentication/4.10.0/get-started Installs the ash_authentication_phoenix extension, specifically for Phoenix applications. This command also configures authentication strategies. ```bash mix igniter.install ash_authentication_phoenix --auth-strategy magic_link,password ``` -------------------------------- ### Install Ash Authentication (Default) Source: https://hexdocs.pm/ash_authentication/4.10.0/Mix.Tasks.AshAuthentication Installs the ash_authentication library with default settings. This command sets up the basic authentication structure for your application. ```bash mix igniter.install ash_authentication ``` -------------------------------- ### Using the Authentication Helper in LiveView Tests Source: https://hexdocs.pm/ash_authentication/4.10.0/testing Demonstrates how to use the `register_and_log_in_user` helper function within LiveView tests. It can be invoked in the `setup` block for automatic setup before each test, or called directly within a `test` block if more granular control is needed. ```elixir defmodule MyAppWeb.MyLiveTest do use MyAppWeb.ConnCase setup :register_and_log_in_user test "some test", %{conn: conn} do {:ok, lv, _html} = live(conn, ~p"/authenticated-route") # ... end end ``` ```elixir test "some test", context do %{conn: conn} = register_and_log_in_user(context) {:ok, lv, _html} = live(conn, ~p"/authenticated-route") # ... end ``` -------------------------------- ### Phoenix HEEx Template for Navigation Bar with User Auth Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started This HEEx template defines a navigation bar for a Phoenix application. It dynamically displays user email and a sign-out button if a user is logged in, or a sign-in button otherwise. It's designed to be placed in `home.html.heex`. ```heex

Demo

``` -------------------------------- ### AshAuthentication Debug Log Example Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started This is an example of a debug log message generated by AshAuthentication when an authentication failure occurs with debug mode enabled. It provides details about the failure, such as 'Query returned no users'. ```log [timestamp] [warning] Authentication failed: Query returned no users Details: %AshAuthentication.Errors.AuthenticationFailed{ field: nil, strategy: %AshAuthentication.Strategy.Password{ confirmation_required?: true, ... ``` -------------------------------- ### Enable Dark Theme Support for Header Images with daisyUI Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started Provides the CSS configuration to enable dark theme support for header images when using daisyUI with Ash Authentication. This ensures `dark:hidden` and `dark:block` classes work correctly with daisyUI's theme system. ```css @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)); ``` -------------------------------- ### Elixir Password Reset Email Sender Module Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started This module, `Example.Accounts.User.Senders.SendPasswordResetEmail`, implements the `AshAuthentication.Sender` behaviour to send a password reset email. It takes a user, a token, and additional data to construct and deliver the reset link. ```elixir defmodule Example.Accounts.User.Senders.SendPasswordResetEmail do @moduledoc """ Sends a password reset email """ use AshAuthentication.Sender use ExampleWeb, :verified_routes @impl AshAuthentication.Sender def send(user, token, _) do Example.Accounts.Emails.deliver_reset_password_instructions( user, url(~p"/password-reset/#{token}") ) end end ``` -------------------------------- ### Enable AshAuthentication Debugging in Development Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started This configuration snippet enables detailed logging for authentication failures in the development environment. It should be added to `config/dev.exs` and is crucial for debugging authentication issues. Do not enable this in production environments. ```elixir config :ash_authentication, debug_authentication_failures?: true ``` -------------------------------- ### Define Ash Authentication User Resource (Elixir) Source: https://hexdocs.pm/ash_authentication/get-started Defines the `User` resource with `AshPostgres.DataLayer` and the `AshAuthentication` extension. It includes attribute definitions, custom actions like `get_by_subject`, token management configuration, and security policies. ```elixir # lib/my_app/accounts/user.ex defmodule MyApp.Accounts.User do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication], authorizers: [Ash.Policy.Authorizer], domain: MyApp.Accounts attributes do uuid_primary_key :id end actions do defaults [:read] read :get_by_subject do description "Get a user by the subject claim in a JWT" argument :subject, :string, allow_nil?: false get? true prepare AshAuthentication.Preparations.FilterBySubject end end authentication do tokens do enabled? true token_resource MyApp.Accounts.Token store_all_tokens? true signing_secret fn _, _ -> # This is a secret key used to sign tokens. See the note below on secrets management Application.fetch_env(:my_app, :token_signing_secret) end end add_ons do log_out_everywhere do apply_on_password_change? true end end end postgres do table "users" repo MyApp.Repo end # You can customize this if you wish, but this is a safe default that # only allows user data to be interacted with via AshAuthentication. policies do bypass AshAuthentication.Checks.AshAuthenticationInteraction do authorize_if always() end policy always() do forbid_if always() end end end ``` -------------------------------- ### Install Ash Authentication (Custom) Source: https://hexdocs.pm/ash_authentication/4.10.0/Mix.Tasks.AshAuthentication Installs the ash_authentication library with custom settings, including authentication strategies, accounts domain, user resource, and token resource. This allows for tailored authentication flows. ```bash mix igniter.install ash_authentication --auth-strategy magic_link,password --accounts MyApp.AshAccounts --user MyApp.AshAccounts.User --token MyApp.AshAccounts.Token ``` -------------------------------- ### Install Ash Authentication Extension Source: https://hexdocs.pm/ash_authentication/4.10.0/get-started Installs the ash_authentication extension using the Igniter mix task. This command configures authentication strategies like magic link and password. ```bash mix igniter.install ash_authentication --auth-strategy magic_link,password ``` -------------------------------- ### Define Ash Authentication Domain (Elixir) Source: https://hexdocs.pm/ash_authentication/get-started Defines a custom Ash domain named `MyApp.Accounts` which registers `User` and `Token` resources. This domain is then added to the application's Ash configuration. ```elixir # lib/my_app/accounts.ex defmodule MyApp.Accounts do use Ash.Domain resources do resource MyApp.Accounts.User resource MyApp.Accounts.Token end end ``` ```elixir # in config/config.exs config :my_app, ash_domains: [..., MyApp.Accounts] ``` -------------------------------- ### Add AshAuthentication Igniter Installer Source: https://hexdocs.pm/ash_authentication/changelog Introduces an installer for the Ash Authentication igniter. This simplifies the setup process for new projects integrating Ash Authentication. ```elixir Add AshAuthentication igniter installer (#782) igniter installer for user & user token resources ``` -------------------------------- ### Support SQLite in Installer Source: https://hexdocs.pm/ash_authentication/changelog This improvement adds support for SQLite in the installer. This expands the range of databases that can be used with the generated authentication setups. ```elixir support sqlite in the installer ``` -------------------------------- ### Respond to `--auth-strategy` Option in Installer Source: https://hexdocs.pm/ash_authentication/changelog Enhances the installer to correctly respond to the `--auth-strategy` command-line option, allowing users to specify the desired authentication strategy during installation. ```elixir respond to `--auth-strategy` option in installer support `--auth-strategy` option when installing ``` -------------------------------- ### Install AshAuthenticationPhoenix (Mix Task) Source: https://hexdocs.pm/ash_authentication/_phoenix/Mix.Tasks.AshAuthenticationPhoenix This code snippet demonstrates how to install the AshAuthenticationPhoenix project using a mix task. The installation process can be customized using various options to specify different resource domains for accounts, users, and tokens. ```bash mix igniter.install ash_authentication_phoenix ``` -------------------------------- ### Security Configuration for Authentication Attributes and Actions Source: https://hexdocs.pm/ash_authentication/get-started Demonstrates how to mark sensitive data like hashed passwords and registration arguments as sensitive using the `sensitive?: true` option in Ash. It also shows how to set `public?: true` for identity fields needed by authentication UIs. ```elixir attributes do # Identity fields - public for authentication UI attribute :email, :ci_string, allow_nil?: false, public?: true # Credentials - always sensitive, never public attribute :hashed_password, :string, allow_nil?: false, sensitive?: true, public?: false end actions do create :register do # Credential arguments - always sensitive argument :password, :string, allow_nil?: false, sensitive?: true argument :password_confirmation, :string, allow_nil?: false, sensitive?: true end end ``` -------------------------------- ### Configure Ash Postgres Extensions (Elixir) Source: https://hexdocs.pm/ash_authentication/get-started Configures the AshPostgres data layer to use specific PostgreSQL extensions, such as 'ash-functions' and 'citext', which are required for certain Ash functionalities. ```elixir # lib/my_app/repo.ex defmodule MyApp.Repo do use AshPostgres.Repo, otp_app: :my_app def installed_extensions do ["ash-functions", "citext"] end end ``` -------------------------------- ### Dispatch Magic Link Sign-In Plug (Elixir) Source: https://hexdocs.pm/ash_authentication/4.9.5/dsl-ashauthentication-strategy-magiclink This example demonstrates how to directly dispatch to the magic link sign-in plug endpoint. It involves requesting a token, constructing a GET request with the token, and then using `Strategy.plug` for the sign-in action, finally verifying the authentication result. ```elixir ...> {:ok, token} = MagicLink.request_token_for(strategy, user) ...> conn = conn(:get, "/user/magic_link", %{"token" => token}) ...> conn = Strategy.plug(strategy, :sign_in, conn) ...> {_conn, {:ok, signed_in_user}} = Plug.Helpers.get_authentication_result(conn) ...> signed_in_user.id == user.id true ``` -------------------------------- ### Setup Token Resource for Authentication Source: https://hexdocs.pm/ash_authentication/4.10.0/get-started Defines the MyApp.Accounts.Token resource, which is essential for token-based authentication. It uses AshPostgres, includes AshAuthentication.TokenResource extension, and sets up basic policies. ```elixir defmodule MyApp.Accounts.Token do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication.TokenResource], authorizers: [Ash.Policy.Authorizer], domain: MyApp.Accounts postgres do table "tokens" repo MyApp.Repo end policies do bypass AshAuthentication.Checks.AshAuthenticationInteraction do authorize_if always() end end end ``` -------------------------------- ### Using the Logged-in User Helper in LiveView Tests (Elixir) Source: https://hexdocs.pm/ash_authentication/4.9.5/testing Demonstrates how to use the `register_and_log_in_user` helper within LiveView tests by passing it to the `setup` function. This ensures the test context includes an authenticated user for testing protected routes. ```elixir defmodule MyAppWeb.MyLiveTest do use MyAppWeb.ConnCase setup :register_and_log_in_user test "some test", %{conn: conn} do {:ok, lv, _html} = live(conn, ~p"/authenticated-route") # ... end end ``` -------------------------------- ### Configure Resettable Password Strategy in User Resource Source: https://hexdocs.pm/ash_authentication/_phoenix/get-started This Elixir code snippet configures the `password` strategy for the `User` resource to be resettable. It specifies an email sender for password reset emails. This code should replace the existing `strategies` block in `lib/example/accounts/user.ex`. ```elixir # [...] strategies do password :password do identity_field :email resettable do sender Example.Accounts.User.Senders.SendPasswordResetEmail end end end ``` -------------------------------- ### AshAuthentication - Configuration Source: https://hexdocs.pm/ash_authentication/AshAuthentication Configuration example for adding AshAuthentication to a resource, including defining authentication strategies and identities. ```APIDOC ## AshAuthentication Resource Configuration ### Description This section details how to configure a resource to use AshAuthentication, including setting up authentication strategies and identities. ### Method Configuration (within resource definition) ### Endpoint N/A ### Parameters #### Resource Attributes - **email** (ci_string) - Required - User's email address. - **hashed_password** (string) - Required, Sensitive - Hashed password for the user. #### Authentication Strategies - **password** (:password) - **identity_field**: (atom) - The field to use for identity (e.g., :email). - **hashed_password_field**: (atom) - The field storing the hashed password. #### Identities - **unique_email**: [:email] - Defines a unique email identity for the user. ### Request Example ```elixir defmodule MyApp.Accounts.User do use Ash.Resource, extensions: [AshAuthentication], domain: MyApp.Accounts attributes do uuid_primary_key :id attribute :email, :ci_string, allow_nil?: false attribute :hashed_password, :string, allow_nil?: false, sensitive?: true end authentication do strategies do password :password do identity_field :email hashed_password_field :hashed_password end end end identities do identity :unique_email, [:email] end end ``` ### Response N/A (This is a configuration example) ``` -------------------------------- ### Elixir Example: Requesting and Signing In with Magic Link Source: https://hexdocs.pm/ash_authentication/4.10.0/dsl-ashauthentication-strategy-magiclink Demonstrates how to programmatically request a magic link token for a user and then use that token to sign the user in. This involves interacting with the `AshAuthentication.Strategy` module. ```elixir iex> strategy = Info.strategy!(Example.User, :magic_link) ...> user = build_user() ...> Strategy.action(strategy, :request, %{"username" => user.username}) :ok ...> {:ok, token} = MagicLink.request_token_for(strategy, user) ...> {:ok, signed_in_user} = Strategy.action(strategy, :sign_in, %{"token" => token}) ...> signed_in_user.id == user true ``` -------------------------------- ### Enabling User Registration and Customizing Actions Source: https://hexdocs.pm/ash_authentication/dsl-ashauthentication-strategy-github This example illustrates how to enable user registration (`registration_enabled?: true`) and specify custom action names for registration (`register_action_name`) and sign-in (`sign_in_action_name`). This allows for tailored user onboarding and authentication flows. ```elixir authentication :oauth2, MyApp.Accounts.OAuth2, registration_enabled?: true, register_action_name: :create_user, sign_in_action_name: :authenticate_user ``` -------------------------------- ### AshAuthentication OAuth2 Strategy Configuration Source: https://hexdocs.pm/ash_authentication/dsl-ashauthentication-strategy-oauth2 Configuration example for integrating the OAuth2 strategy into an Ash.Resource. ```APIDOC ## Ash.Resource with OAuth2 Strategy ### Description This example demonstrates how to configure an Ash.Resource to use the `AshAuthentication.Strategy.OAuth2` for user authentication. ### Method N/A (DSL Configuration) ### Endpoint N/A (DSL Configuration) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example ```elixir defmodule MyApp.Accounts.User do use Ash.Resource, extensions: [AshAuthentication], domain: MyApp.Accounts attributes do uuid_primary_key :id attribute :email, :ci_string, allow_nil?: false end authentication do strategies do oauth2 :example do client_id "OAuth Client ID" redirect_uri "https://my.app/" client_secret "My Super Secret Secret" site "https://auth.example.com/" end end end end ``` ### Response N/A (DSL Configuration) #### Success Response (200) N/A #### Response Example N/A ``` -------------------------------- ### Setup Options Properly for Ash 3.0 Source: https://hexdocs.pm/ash_authentication/changelog Ensures that options are set up correctly to be compatible with Ash version 3.0, addressing potential integration issues. ```elixir setup options properly for ash 3.0 (#785) ``` -------------------------------- ### Define Load From Session Plug - Elixir Source: https://hexdocs.pm/ash_authentication/4.9.5/AshAuthentication.Plug Generates the `load_from_session/2` plug with the `otp_app` prefilled. This macro simplifies session-based authentication setup within AshAuthentication. ```elixir define_load_from_session(otp_app) @spec define_load_from_session(atom()) :: Macro.t() Generates the `load_from_session/2` plug with the `otp_app` prefilled. ``` -------------------------------- ### Customizing Authentication Actions (Elixir) Source: https://hexdocs.pm/ash_authentication/4.10.0/get-started Demonstrates how to customize authentication actions like 'register' by adding required changes specific to the strategy. Includes examples for the password and OAuth2 strategies, showing how to define custom arguments and logic. ```elixir # Password registration create :register_with_password do # Your custom arguments and logic... # Required for password strategy: change AshAuthentication.GenerateTokenChange change AshAuthentication.Strategy.Password.HashPasswordChange end # OAuth2 registration create :register_with_github do argument :user_info, :map, allow_nil?: false argument :oauth_tokens, :map, allow_nil?: false, sensitive?: true # Required for OAuth2: change AshAuthentication.GenerateTokenChange change AshAuthentication.Strategy.OAuth2.IdentityChange # Extract user data from OAuth response: change fn changeset, _ctx -> user_info = Ash.Changeset.get_argument(changeset, :user_info) Ash.Changeset.change_attributes(changeset, Map.take(user_info, ["email", "name"])) end end ``` -------------------------------- ### Elixir Example: Dispatching Magic Link Plugs Directly Source: https://hexdocs.pm/ash_authentication/4.10.0/dsl-ashauthentication-strategy-magiclink Illustrates how to directly dispatch to the magic link strategy's plug endpoints for both requesting a link and signing in. This involves manually creating and manipulating a Plug connection. ```elixir iex> strategy = Info.strategy!(Example.User, :magic_link) ...> user = build_user() ...> conn = conn(:post, "/user/magic_link/request", %{"user" => %{"username" => user.username}}) ...> conn = Strategy.plug(strategy, :request, conn) ...> {_conn, {:ok, nil}} = Plug.Helpers.get_authentication_result(conn) ...> {:ok, token} = MagicLink.request_token_for(strategy, user) ...> conn = conn(:get, "/user/magic_link", %{"token" => token}) ...> conn = Strategy.plug(strategy, :sign_in, conn) ...> {_conn, {:ok, signed_in_user}} = Plug.Helpers.get_authentication_result(conn) ...> signed_in_user.id == user.id true ``` -------------------------------- ### AshAuthentication.TokenResource Usage Source: https://hexdocs.pm/ash_authentication/dsl-ashauthentication-tokenresource Example of how to define a Token resource using AshAuthentication.TokenResource extension. ```APIDOC ## `AshAuthentication.TokenResource` Usage There is no need to define any attributes or actions (although you can if you want). The extension will wire up everything that's needed for the token system to function. ### Example Usage ```elixir defmodule MyApp.Accounts.Token do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication.TokenResource], domain: MyApp.Accounts postgres do table "tokens" repo MyApp.Repo end end ``` Whilst it is possible to have multiple token resources, there is no need to do so. ``` -------------------------------- ### Sign In with Magic Link Token (Elixir) Source: https://hexdocs.pm/ash_authentication/4.9.5/dsl-ashauthentication-strategy-magiclink This example demonstrates how to sign in a user using a magic link token. It first requests a token using `MagicLink.request_token_for` and then uses `Strategy.action` with the `:sign_in` action and the received token to authenticate the user. ```elixir ...> {:ok, token} = MagicLink.request_token_for(strategy, user) ...> {:ok, signed_in_user} = Strategy.action(strategy, :sign_in, %{"token" => token}) ...> signed_in_user.id == user true ``` -------------------------------- ### Ash Authentication Plug Setup (Elixir) Source: https://hexdocs.pm/ash_authentication/4.10.0/get-started Defines a custom plug for handling authentication requests in Phoenix or Plug applications. It includes callbacks for successful and failed authentication attempts, distinguishing between API requests (JSON) and standard web requests. ```elixir # lib/my_app/auth_plug.ex defmodule MyApp.AuthPlug do use AshAuthentication.Plug, otp_app: :my_app def handle_success(conn, _activity, user, token) do if is_api_request?(conn) do conn |> send_resp(200, Jason.encode!(%{ authentication: %{ success: true, token: token } })) else conn |> store_in_session(user) |> send_resp(200, EEx.eval_string("""

Welcome back <%= @user.email %>

""", user: user)) end end def handle_failure(conn, _activity, _reason) do if is_api_request?(conn) do conn |> send_resp(401, Jason.encode!(%{ authentication: %{ success: false } })) else conn |> send_resp(401, "

Incorrect email or password

") end end defp is_api_request?(conn), do: "application/json" in get_req_header(conn, "accept") end ``` -------------------------------- ### Customizing Password Registration Action Source: https://hexdocs.pm/ash_authentication/4.9.5/get-started Example of customizing the 'register' action for the password strategy. It includes essential changes like token generation and password hashing, along with custom logic if needed. ```elixir # Password registration create :register_with_password do # Your custom arguments and logic... # Required for password strategy: change AshAuthentication.GenerateTokenChange change AshAuthentication.Strategy.Password.HashPasswordChange end ``` -------------------------------- ### Define Strategy Phases and Actions Source: https://hexdocs.pm/ash_authentication/custom-strategy Defines the available phases and actions for the authentication strategy. This example specifies a single `:sign_in` phase and action. ```elixir defimpl AshAuthentication.Strategy, for: OnlyMartiesAtTheParty do def phases(_), do: [:sign_in] def actions(_), do: [:sign_in] end ``` -------------------------------- ### Implement Email Confirmation Instructions in Elixir Source: https://hexdocs.pm/ash_authentication/4.10.0/confirmation This Elixir module provides a function to deliver email confirmation instructions. It constructs an email with a confirmation link and uses a private `deliver` function to send the email. This example uses `Swoosh.Email` and `MyApp.Mailer` for sending emails. ```elixir defmodule Example.Accounts.Emails do @moduledoc """ Delivers emails. """ import Swoosh.Email def deliver_email_confirmation_instructions(user, url) do if !url do raise "Cannot deliver confirmation instructions without a url" end deliver(user.email, "Confirm your email address", """

Hi #{user.email},

Someone has tried to register a new account using this email address. If it was you, then please click the link below to confirm your identity. If you did not initiate this request then please ignore this email.

Click here to confirm your account

""" | ) 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) |> MyApp.Mailer.deliver!() end end ``` -------------------------------- ### AshAuthentication OAuth2 Secret Management Source: https://hexdocs.pm/ash_authentication/dsl-ashauthentication-strategy-oauth2 Examples of how to manage secrets and runtime configuration for the OAuth2 strategy. ```APIDOC ## AshAuthentication OAuth2 Secret Management ### Description Demonstrates different methods for providing secrets and runtime configuration for the OAuth2 authentication strategy, emphasizing security best practices. ### Method N/A (DSL Configuration) ### Endpoint N/A (DSL Configuration) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example **Providing configuration as an anonymous function:** ```elixir oauth2 do client_secret fn _path, resource -> Application.fetch_env(:my_app, resource, :oauth2_client_secret) end end ``` **Providing configuration as a module:** ```elixir defmodule MyApp.Secrets do use AshAuthentication.Secret def secret_for([:authentication, :strategies, :example, :client_secret], MyApp.User, _opts), do: Application.fetch_env(:my_app, :oauth2_client_secret) end # And in your strategies: oauth2 :example do client_secret MyApp.Secrets end ``` ### Response N/A (DSL Configuration) #### Success Response (200) N/A #### Response Example N/A ``` -------------------------------- ### Ash User Resource with Password Strategy Source: https://hexdocs.pm/ash_authentication/4.10.0/confirmation Defines a User resource using Ash with the AshAuthentication extension and a password authentication strategy. It includes basic attributes like email and hashed_password, and an identity for unique emails. This serves as the starting point for the confirmation tutorial. ```elixir defmodule MyApp.Accounts.User do use Ash.Resource, extensions: [AshAuthentication], domain: MyApp.Accounts attributes do uuid_primary_key :id attribute :email, :ci_string, allow_nil?: false, public?: true, sensitive?: true attribute :hashed_password, :string, allow_nil?: false, public?: false, sensitive?: true end authentication do strategies do password :password do identity_field :email hashed_password_field :hashed_password end end end identities do identity :unique_email, [:email] end end ```