### Example Two-Step TOTP Setup Flow Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/totp.md Demonstrates the three steps for initiating, displaying, and confirming TOTP setup. The secret is only stored on the user after successful confirmation. ```elixir # Step 1: Initiate setup {:ok, user} = Ash.update(user, action: :setup_with_totp) setup_token = user.__metadata__.setup_token totp_url = user.__metadata__.totp_url # Step 2: Display QR code (use totp_url with a QR code library) # The URL format is: otpauth://totp/Issuer:user@example.com?secret=BASE32SECRET&issuer=Issuer # Step 3: User scans QR code and enters the code from their app {:ok, user} = Ash.update(user, action: :confirm_setup_with_totp, params: %{setup_token: setup_token, code: "123456"} ) # User now has TOTP enabled ``` -------------------------------- ### Password Strategy Configuration Example Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.Password.md An example of configuring the password strategy with additional options like hash provider and password confirmation. ```elixir password :password do identity_field :email hashed_password_field :hashed_password hash_provider AshAuthentication.BcryptProvider confirmation_required? true end ``` -------------------------------- ### Quick Setup with Igniter Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/okta.md Use this mix task for the fastest way to add Okta authentication. It generates the necessary resources, actions, and wiring. Follow the printed instructions for Okta application registration and environment variable setup. ```bash mix ash_authentication.add_strategy okta ``` -------------------------------- ### Two-Step TOTP Setup with Confirmation Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/totp.md Enable two-step TOTP setup for enhanced security. This requires enabling tokens, setting `confirm_setup_enabled?` to true, and configuring `setup_token_lifetime`. ```elixir authentication do tokens do enabled? true token_resource MyApp.Accounts.Token end strategies do totp do identity_field :email confirm_setup_enabled? true setup_token_lifetime {10, :minutes} brute_force_strategy {:preparation, MyApp.TotpBruteForcePreparation} end end end ``` -------------------------------- ### Install Ash Authentication Extension Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/get-started.md Use the `mix igniter.install` command to install the `ash_authentication` extension. You can specify authentication strategies like `magic_link` and `password`. ```shell mix igniter.install ash_authentication --auth-strategy magic_link,password ``` -------------------------------- ### Install Ash Authentication Phoenix Extension Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/get-started.md For Phoenix applications, use `mix igniter.install ash_authentication_phoenix`. This command will prompt for installation if not already done. ```shell mix igniter.install ash_authentication_phoenix --auth-strategy magic_link,password ``` -------------------------------- ### Dynamic OIDC URL Structure Examples Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/dynamic-oidc.md Illustrates the URL patterns for initiating sign-in and handling callbacks with the dynamic OIDC strategy. ```text GET /auth/user/sso//request GET /auth/user/sso/callback ``` -------------------------------- ### Define Strategy Actions Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/custom-strategy.md Defines the actions supported by the strategy. This example supports only a `:sign_in` action. ```elixir def actions(_), do: [:sign_in] ``` -------------------------------- ### Define Strategy Phases Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/custom-strategy.md Defines the phases supported by the strategy. This example supports only a `:sign_in` phase. ```elixir def phases(_), do: [:sign_in] ``` -------------------------------- ### API Key Policy Example Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.ApiKey.md Example of how to define a policy that authorizes actions when using an API key. This policy checks if the user is signed in with an API key and allows specific actions. ```elixir policy AshAuthentication.Checks.UsingApiKey do authorize_if action([:a, :list, :of, :allowed, :action, :names]) end ``` -------------------------------- ### Setup Token Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/get-started.md Define the `Token` resource using `Ash.Resource` with `AshPostgres.DataLayer` and the `AshAuthentication.TokenResource` extension. Configure policies if needed. ```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 ``` -------------------------------- ### Using the Login Helper in LiveView Tests Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/testing.md Incorporate the `register_and_log_in_user` helper within your LiveView tests using the `setup` function. This ensures the user is logged in before the test runs. ```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 ``` -------------------------------- ### Full WebAuthn Credential Resource Example Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.WebAuthn.md Defines the Ash resource for storing WebAuthn credentials, including attributes, relationships, and actions. This is a comprehensive example for setting up the credential storage. ```elixir defmodule MyApp.Accounts.Credential do use Ash.Resource, domain: MyApp.Accounts, data_layer: AshPostgres.DataLayer, authorizers: [Ash.Policy.Authorizer] postgres do table "webauthn_credentials" repo(MyApp.Repo) end policies do bypass AshAuthentication.Checks.AshAuthenticationInteraction do authorize_if always() end policy always() do authorize_if always() end end attributes do uuid_primary_key :id attribute :credential_id, :binary, allow_nil?: false, public?: true attribute :public_key, AshAuthentication.Strategy.WebAuthn.CoseKey, allow_nil?: false, public?: true attribute :sign_count, :integer, default: 0, allow_nil?: false, public?: true attribute :label, :string, default: "Security Key", public?: true attribute :last_used_at, :utc_datetime_usec, public?: true create_timestamp :inserted_at update_timestamp :updated_at end relationships do belongs_to :user, MyApp.Accounts.User, allow_nil?: false, public?: true end identities do identity :unique_credential_id, [:credential_id] end actions do defaults [:read, :destroy] create :create do primary? true accept [:credential_id, :public_key, :sign_count, :label, :user_id] end update :update do primary? true accept [:sign_count, :label, :last_used_at] end end end ``` -------------------------------- ### Transform Strategy and DSL State Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/custom-strategy.md This example shows how to modify both the strategy configuration and the resource's DSL state. It generates a sign-in action and registers it. ```elixir def transform(strategy, dsl_state) do strategy = Map.put_new(strategy, :sign_in_action_name, :"sign_in_with_#{strategy.name}") sign_in_action = Spark.Dsl.Transformer.build_entity(Ash.Resource.Dsl, [:actions], :read, name: strategy.sign_in_action_name, accept: [strategy.name_field], get?: true ) dsl_state = dsl_state |> Spark.Dsl.Transformer.add_entity([:actions], sign_in_action) |> put_strategy(strategy) |> then(fn dsl_state -> register_strategy_actions([strategy.sign_in_action_name], dsl_state, strategy) end) {:ok, dsl_state} end ``` -------------------------------- ### Customize Audit Log Installation Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md Customize the audit log add-on installation with options for resource name, including sensitive fields, and excluding specific strategies or actions. ```bash # Custom audit log resource name mix ash_authentication.add_add_on audit_log --audit-log MyApp.Accounts.AuthAuditLog # Include sensitive fields mix ash_authentication.add_add_on audit_log --include-fields email,username # Exclude specific strategies mix ash_authentication.add_add_on audit_log --exclude-strategies magic_link,oauth # Exclude specific actions mix ash_authentication.add_add_on audit_log --exclude-actions sign_in_with_token ``` -------------------------------- ### Install Audit Log Add-on Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md Use this mix task to automatically set up the audit log add-on. It creates the necessary resource, adds the add-on to your user resource, and ensures the supervisor is in place. ```bash mix ash_authentication.add_add_on audit_log ``` -------------------------------- ### Multi-Tenancy Callback Implementations Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.WebAuthn.md Provides example implementations for multi-tenant callbacks used in WebAuthn configuration. These functions dynamically generate `rp_id`, `rp_name`, and `origin` based on the tenant. ```elixir defmodule MyApp.WebAuthn do def rp_id_for_tenant(tenant), do: "#{tenant}.example.com" def rp_name_for_tenant(tenant), do: "MyApp - #{tenant}" def origin_for_tenant(tenant), do: "https://#{tenant}.example.com" end ``` -------------------------------- ### Define HTTP Method for Phase Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/custom-strategy.md Specifies the HTTP method to use for a given phase. This example uses `:post` for the `:sign_in` phase. ```elixir def method_for_phase(_, :sign_in), do: :post ``` -------------------------------- ### Basic TOTP Setup for 2FA Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/totp.md Configure the `totp` authentication strategy for two-factor authentication. This requires specifying an `identity_field` and a `brute_force_strategy`. ```elixir authentication do strategies do password :password do identity_field :email end totp do identity_field :email # Required: choose a brute force protection strategy brute_force_strategy {:preparation, MyApp.TotpBruteForcePreparation} end end end ``` -------------------------------- ### Add GitHub Strategy with Igniter Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/github.md Use this command to quickly add the GitHub authentication strategy to your Ash Authentication setup. It generates necessary resources, actions, and wiring. Follow the on-screen instructions to complete the setup. ```bash mix ash_authentication.add_strategy github ``` -------------------------------- ### Define a Token Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.TokenResource.md This example shows how to define a token resource using the AshAuthentication.TokenResource extension. It specifies the data layer, the domain, and the database table and repository. ```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 ``` -------------------------------- ### Define Custom Strategy Module Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/custom-strategy.md Start by defining a module for your custom strategy. This module will use the `AshAuthentication.Strategy.Custom` macro. ```elixir defmodule OnlyMartiesAtTheParty do use AshAuthentication.Strategy.Custom end ``` -------------------------------- ### Complete Token Resource Configuration for Auto Sign-out Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/auto-signout.md A complete example of the Token resource configuration, including notifiers and endpoint settings, required for auto sign-out functionality. ```elixir defmodule MyApp.Accounts.Token do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication.TokenResource], domain: MyApp.Accounts, notifiers: [AshAuthentication.Phoenix.TokenRevocationNotifier] postgres do table "tokens" repo MyApp.Repo end token do endpoints [MyAppWeb.Endpoint] live_socket_id_template fn %{jti: jti} -> "users_sessions:#{jti}" end end end ``` -------------------------------- ### Complete User Resource with Log Out Everywhere Add-on Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/auto-signout.md Example configuration for the User resource, enabling token authentication and integrating the 'log_out_everywhere' add-on to handle password changes by revoking all user tokens. ```elixir defmodule MyApp.Accounts.User do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication], domain: MyApp.Accounts authentication do tokens do enabled? true token_resource MyApp.Accounts.Token store_all_tokens? true end strategies do password :password do identity_field :email end end add_ons do log_out_everywhere do apply_on_password_change? true end end end # ... attributes, identities, etc. ``` -------------------------------- ### Basic WebAuthn Strategy Configuration Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.WebAuthn.md A basic example of configuring the WebAuthn strategy, specifying the credential resource, relying party ID, relying party name, and the identity field for user lookup. ```elixir webauthn :webauthn do credential_resource MyApp.Accounts.Credential rp_id "example.com" rp_name "My App" identity_field :email end ``` -------------------------------- ### Configure Confirmation AddOn for User Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.AddOn.Confirmation.md Example of adding the confirmation add-on to an Ash resource, specifying fields to monitor and a custom sender. ```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 add_ons do confirmation :confirm do monitor_fields [:email] sender MyApp.ConfirmationSender end end strategies do # ... end end identities do identity :email, [:email] end end ``` -------------------------------- ### Implement Confirmation Email Sender Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/confirmation.md Create a sender module that implements the AshAuthentication.Sender behaviour to send confirmation emails. This example uses verified routes to generate the confirmation URL. ```elixir defmodule MyApp.Accounts.User.Senders.SendNewUserConfirmationEmail do @moduledoc """ Sends an email confirmation email """ use AshAuthentication.Sender use MyAppWeb, :verified_routes @impl AshAuthentication.Sender def send(user, token, _opts) do MyApp.Accounts.Emails.deliver_email_confirmation_instructions( user, url(~p"/confirm_new_user/#{token}") ) end end ``` -------------------------------- ### Email Template for Confirmation Instructions Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/confirmation.md Define an email template for sending confirmation instructions. This example includes a basic HTML structure and uses Swoosh for email delivery. Remember to replace placeholder email details. ```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 ``` -------------------------------- ### Add Slack Authentication Strategy with Igniter Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/slack.md Use this command to quickly add Slack authentication to your project. It generates necessary resources, actions, and wiring. Follow the on-screen instructions to complete the setup. ```bash mix ash_authentication.add_strategy slack ``` -------------------------------- ### Get and List Authentication Strategies Source: https://github.com/team-alembic/ash_authentication/blob/main/CLAUDE.md Retrieve a specific authentication strategy for a user resource or list all available strategies. This is useful for dynamic authentication flows. ```elixir # Get and use strategies strategy = AshAuthentication.Info.strategy!(MyApp.User, :password) {:ok, user} = AshAuthentication.Strategy.action(strategy, :sign_in, params) # List strategies strategies = AshAuthentication.Info.strategies(MyApp.User) ``` -------------------------------- ### User Resource with TOTP Strategy Configuration Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.Totp.md Example of a User resource configured with the AshAuthentication extension and the TOTP strategy. This includes defining necessary attributes like totp_secret and last_totp_at, enabling tokens, and setting up the TOTP strategy with an identity field, issuer, and brute force protection via an audit log. ```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 attribute :totp_secret, :binary, sensitive?: true attribute :last_totp_at, :utc_datetime, sensitive?: true end authentication do tokens do enabled? true token_resource MyApp.Accounts.Token end strategies do totp do identity_field :email issuer "MyApp" brute_force_strategy {:audit_log, :my_audit_log} end end add_ons do audit_log :my_audit_log do audit_log_resource MyApp.Accounts.AuditLog log_actions [:sign_in_with_totp, :verify_with_totp, :confirm_setup_with_totp] end end end identities do identity :unique_email, [:email] end end ``` -------------------------------- ### Custom OTP Generator Module Implementation Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/otp.md Provides an example implementation for a custom OTP generator module. The module must export `generate/1` for code creation and `normalize/1` for consistent code matching during sign-in. ```elixir defmodule MyApp.Accounts.OtpGenerator do def generate(opts) do length = Keyword.get(opts, :length, 6) # your implementation here end def normalize(code) do String.trim(code) end end ``` -------------------------------- ### Define Policies for Audit Logs Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md This example shows how to define read and create policies for an audit log resource using Ash. Admins can read logs, and AshAuthentication is authorized to create them. ```elixir defmodule MyApp.Accounts.AuditLog do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication.AuditLogResource], domain: MyApp.Accounts, authorizers: [Ash.Policy.Authorizer] policies do # Only admins can read audit logs policy action_type(:read) do authorize_if relates_to_actor_via([:user, :admin]) end # Allow AshAuthentication to write logs policy action_type(:create) do authorize_if AshAuthentication.Checks.AshAuthenticationInteraction end end postgres do table "account_audit_log" repo MyApp.Repo end end ``` -------------------------------- ### Define User Identity Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.UserIdentity.md This example shows how to define a user identity resource using the AshAuthentication.UserIdentity extension. It specifies the data layer, the extension, the domain, and the associated user resource. ```elixir defmodule MyApp.Accounts.UserIdentity do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication.UserIdentity], domain: MyApp.Accounts user_identity do user_resource MyApp.Accounts.User end postgres do table "user_identities" repo MyApp.Repo end end ``` -------------------------------- ### API Key Filtering Example Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/api-keys.md An example of how to filter API keys based on validity in a relationship definition. ```elixir has_many :valid_api_keys, MyApp.Accounts.ApiKey do filter expr(valid) end ``` -------------------------------- ### Implement Sign-In Action Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/custom-strategy.md Implements the sign-in action, querying for users matching the input name and a specific prefix. Handles cases for zero, one, or multiple matching users. ```elixir alias AshAuthentication.Errors.AuthenticationFailed require Ash.Query import Ash.Expr def action(strategy, :sign_in, params, options) do name_field = strategy.name_field name = Map.get(params, to_string(name_field)) domain = AshAuthentication.Info.domain!(strategy.resource) strategy.resource |> Ash.Query.filter(expr(^ref(name_field) == ^name)) |> then(fn query -> if strategy.case_sensitive? do Ash.Query.filter(query, like(^ref(name_field), "Marty%")) else Ash.Query.filter(query, ilike(^ref(name_field), "Marty%")) end end) |> Ash.read(options) |> case do {:ok, [user]} -> {:ok, user} {:ok, []} -> ``` -------------------------------- ### Exclude IP Addresses Entirely Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md Example configuration to completely exclude IP addresses from audit logs. ```elixir # Exclude IP addresses entirely audit_log do audit_log_resource MyApp.Accounts.AuditLog ip_privacy_mode :exclude end ``` -------------------------------- ### Implement Strategy Protocol Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/custom-strategy.md This is the initial implementation of the Strategy protocol for a custom strategy. ```elixir defimpl AshAuthentication.Strategy, for: OnlyMartiesAtTheParty do ``` -------------------------------- ### Hash IP Addresses for Privacy Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md Example configuration to hash all IP addresses using SHA256 for enhanced privacy. ```elixir # Hash all IP addresses for privacy audit_log do audit_log_resource MyApp.Accounts.AuditLog ip_privacy_mode :hash end ``` -------------------------------- ### Generate and Run Migrations Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md Generate migrations for the audit log table and then apply them to your database. ```bash mix ash.codegen create_accounts_audit_logs mix ash.migrate ``` -------------------------------- ### Configure Confirmation Route in AshAuthenticationPhoenix Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.AddOn.Confirmation.md Example of adding a confirm_route to a Phoenix router when using AshAuthenticationPhoenix with require_interaction? set to true. ```elixir # Remove this if you do not want to use the confirmation strategy confirm_route( MyApp.Accounts.User, :confirm_new_user, auth_routes_prefix: "/auth", overrides: [MyApp.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default] ) ``` -------------------------------- ### Generate Account Confirmation Migrations Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/confirmation.md Run this mix task to generate the necessary migrations for adding the 'confirmed_at' column to your user resource, which is required for account confirmation. ```bash mix ash.codegen account_confirmation ``` -------------------------------- ### Add Sign-in with API Key Action Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/api-keys.md Implements the action for signing in using an API key, including necessary preparation. ```elixir read :sign_in_with_api_key do argument :api_key, :string, allow_nil?: false prepare AshAuthentication.Strategy.ApiKey.SignInPreparation end ``` -------------------------------- ### Implement Strategy Plug Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/custom-strategy.md Implements the plug for the strategy, handling sign-in requests by taking the name field from params and storing the authentication result. ```elixir import AshAuthentication.Plug.Helpers, only: [store_authentication_result: 2] def plug(strategy, :sign_in, conn) do params = Map.take(conn.params, [to_string(strategy.name_field)]) result = action(strategy, :sign_in, params, []) store_authentication_result(conn, result) end ``` -------------------------------- ### Truncate IP Addresses with Custom Masks Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md Example configuration for truncating IP addresses with custom network masks for more aggressive privacy. ```elixir # Truncate with more aggressive masking audit_log do audit_log_resource MyApp.Accounts.AuditLog ip_privacy_mode :truncate ipv4_truncation_mask 16 # Keep first 2 octets (more privacy) ipv6_truncation_mask 32 # Keep first 2 segments (more privacy) end ``` -------------------------------- ### Calling Login Helper Directly in a Test Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/testing.md Demonstrates how to call the `register_and_log_in_user` helper directly within a test block if needed, providing the logged-in connection for subsequent LiveView interactions. ```elixir test "some test", context do %{conn: conn} = register_and_log_in_user(context) {:ok, lv, _html} = live(conn, ~p"/authenticated-route") # ... end ``` -------------------------------- ### Add Password Strategy with Mix Task Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/get-started.md Use the provided mix task to add the password authentication strategy to your Ash Authentication setup. ```sh mix ash_authentication.add_strategy password ``` -------------------------------- ### Interacting with TOTP Actions Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.Totp.md Demonstrates how to interact with the TOTP strategy's actions programmatically. Shows how to set up a TOTP secret for a user and how to verify a TOTP code. ```elixir iex> strategy = AshAuthentication.Info.strategy!(MyApp.Accounts.User, :totp) ...> {:ok, user} = AshAuthentication.Strategy.action(strategy, :setup, %{user: existing_user}) ...> user.totp_url_for_totp # QR code URL ``` ```elixir iex> {:ok, true} = AshAuthentication.Strategy.action(strategy, :verify, %{user: user, code: "123456"}) ``` -------------------------------- ### Verification with Bcrypt (Non-Deterministic Hash) Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/recovery-code-security.md Illustrates the verification process for non-deterministic hashes like Bcrypt. This requires selecting records for update, iterating through stored hashes to find a match, and then deleting the matched record. Padding is used to maintain constant time. ```sql SELECT * FROM recovery_codes WHERE user_id = ? FOR UPDATE ``` ```sql DELETE FROM recovery_codes WHERE id = ? ``` ```sql Pad remaining iterations with simulate() for constant time ``` -------------------------------- ### Define Accounts Domain Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/get-started.md Create an `Accounts` domain using `Ash.Domain` and define `User` and `Token` resources within it. ```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 ``` -------------------------------- ### Define OIDC Connection Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.OidcConnection.md Example of defining an Ash resource that uses the `AshAuthentication.OidcConnection` extension. This resource will store dynamic OIDC client configurations. ```elixir defmodule MyApp.Accounts.OidcConnection do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication.OidcConnection], domain: MyApp.Accounts oidc_connection do # All defaults shown — override only what you need. base_url_field :base_url client_id_field :client_id client_secret_field :client_secret display_name_field :display_name icon_url_field :icon_url end postgres do table "oidc_connections" repo MyApp.Repo end end ``` -------------------------------- ### Install Recovery Code Strategy with Igniter Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/recovery-codes.md Use the Igniter mix task to automatically add the recovery code strategy, resource, and relationship to your user resource. ```bash mix ash_authentication.add_strategy recovery_code ``` -------------------------------- ### Render QR Code with EQRCode Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/totp.md Demonstrates how to use the `eqrcode` library to encode the TOTP URL and render it as an SVG. ```elixir # With eqrcode qr_code = EQRCode.encode(qr_url) svg = EQRCode.svg(qr_code) ``` -------------------------------- ### Configure Google Authentication Strategy Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.Google.md This snippet shows the basic configuration for the Google authentication strategy within an AshAuthentication setup. It requires a unique name for the strategy. ```elixir google name \ :google ``` -------------------------------- ### Start Audit Log Supervisor Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md Add the `AshAuthentication.Supervisor` to your application's supervision tree to enable batched writes for audit logs, which helps reduce database load. ```elixir defmodule MyApp.Application do use Application def start(_type, _args) do children = [ MyApp.Repo, # Add this line {AshAuthentication.Supervisor, otp_app: :my_app} ] opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) end end ``` -------------------------------- ### Configure PostgreSQL Extensions Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/get-started.md Ensure your `MyApp.Repo` module lists necessary PostgreSQL extensions like `ash-functions` and `citext` in `installed_extensions/0`. ```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 ``` -------------------------------- ### Add Subject Attribute to Token Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/upgrading.md This example shows how to add the 'subject' attribute to the TokenResource with allow_nil? set to true, which is a workaround for migration errors when upgrading to version 3.6.0. ```elixir attributes do attribute :subject, :string, allow_nil?: true end ``` -------------------------------- ### Generate and Run Migrations Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/auth0.md Commands to generate and apply database migrations for Ash. ```bash mix ash_postgres.generate_migrations mix ecto.migrate ``` -------------------------------- ### Define Audit Log Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/tutorials/audit-log.md Manually create a resource to store audit logs using the `AshAuthentication.AuditLogResource` extension. This extension handles the necessary setup for logging authentication events. ```elixir defmodule MyApp.Accounts.AuditLog do use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshAuthentication.AuditLogResource], domain: MyApp.Accounts postgres do table "account_audit_logs" repo MyApp.Repo end end ``` -------------------------------- ### Configure Auth0 Strategy Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.Auth0.md This Elixir code snippet shows how to define and configure the Auth0 authentication strategy within your AshAuthentication setup. It uses the `:auth0` atom to name the strategy. ```elixir auth0 name \\ :auth0 ``` -------------------------------- ### Signing In with a Magic Link Token Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.MagicLink.md Demonstrates signing in using a magic link token. This involves first requesting a token and then using that 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 ``` -------------------------------- ### Configure WebAuthn Strategy in User Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.WebAuthn.md Example of configuring the WebAuthn strategy within an Ash user resource. Ensure to set up token and credential resources, and define the identity field. ```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 tokens do enabled? true token_resource MyApp.Accounts.Token signing_secret fn _, _ -> {:ok, Application.get_env(:my_app, :token_secret)} end end strategies do webauthn :webauthn do credential_resource MyApp.Accounts.Credential rp_id "example.com" rp_name "My App" origin "https://example.com" identity_field :email end end end relationships do has_many :webauthn_credentials, MyApp.Accounts.Credential end identities do identity :unique_email, [:email] end end ``` -------------------------------- ### Helper to Register and Log In User in ConnCase Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/topics/testing.md Add a helper function to MyApp.ConnCase to seed a test user and log them in directly. This is more efficient than simulating UI logins for testing authenticated LiveViews. ```elixir defmodule MyAppWeb.ConnCase do use ExUnit.CaseTemplate using do # ... end def register_and_log_in_user(%{conn: conn} = context) do email = "user@example.com" password = "password" {:ok, hashed_password} = AshAuthentication.BcryptProvider.hash(password) Ash.Seed.seed!(MyApp.Accounts.User, %{ email: email, hashed_password: hashed_password }) # Replace `:password` with the appropriate strategy for your application. strategy = AshAuthentication.Info.strategy!(MyApp.Accounts.User, :password) {:ok, user} = AshAuthentication.Strategy.action(strategy, :sign_in, %{ email: email, password: password }) new_conn = conn |> Phoenix.ConnTest.init_test_session(%{}) |> AshAuthentication.Plug.Helpers.store_in_session(user) %{context | conn: new_conn} end end ``` -------------------------------- ### Define Password Strategy in Resource Source: https://github.com/team-alembic/ash_authentication/blob/main/documentation/dsls/DSL-AshAuthentication.Strategy.Password.md Example of how to define the password authentication strategy within an Ash resource. Ensure the resource has a primary key, an identity field, and a hashed password field. ```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 ```