View Source AshAuthentication.Strategy.MagicLink (ash_authentication v4.0.0)

Strategy for authentication using a magic link.

In order to use magic link authentication your resource needs to meet the following minimum requirements:

  1. Have a primary key.
  2. A uniquely constrained identity field (eg username or email)
  3. Have tokens enabled.

There are other options documented in the DSL.

Example

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
      magic_link do
        identity_field :email
        sender fn user, token, _opts ->
          MyApp.Emails.deliver_magic_link(user, token)
        end
      end
    end
  end

  identities do
    identity :unique_email, [:email]
  end
end

Actions

By default the magic link strategy will automatically generate the request and sign-in actions for you, however you're free to define them yourself. If you do, then the action will be validated to ensure that all the needed configuration is present.

If you wish to work with the actions directly from your code you can do so via the AshAuthentication.Strategy protocol.

Examples

Requesting that a magic link token is sent for a user:

iex> strategy = Info.strategy!(Example.User, :magic_link)
...> user = build_user()
...> Strategy.action(strategy, :request, %{"username" => user.username})
:ok

Signing in using a magic link token:

...> {: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

Plugs

The magic link strategy provides plug endpoints for both request and sign-in actions.

If you wish to work with the plugs directly, you can do so via the AshAuthentication.Strategy protocol.

Examples:

Dispatching to plugs directly:

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

See the Magic Link Tutorial for more information.

Summary

Types

@type t() :: %AshAuthentication.Strategy.MagicLink{
  identity_field: atom(),
  name: atom(),
  request_action_name: atom(),
  resource: module(),
  sender: {module(), keyword()},
  sign_in_action_name: atom(),
  single_use_token?: boolean(),
  strategy_module: module(),
  token_lifetime: pos_integer(),
  token_param_name: atom()
}

Functions

Link to this function

request_token_for(strategy, user)

View Source
@spec request_token_for(t(), Ash.Resource.record()) :: {:ok, binary()} | :error

Generate a magic link token for a user.

Used by AshAuthentication.Strategy.MagicLink.RequestPreparation.

Link to this function

transform(entity, dsl_state)

View Source

Callback implementation for AshAuthentication.Strategy.Custom.transform/2.

Link to this function

verify(strategy, dsl_state)

View Source

Callback implementation for AshAuthentication.Strategy.Custom.verify/2.