AshAuthentication.Strategy.MagicLink
View SourceStrategy for authentication using a magic link.
In order to use magic link authentication your resource needs to meet the following minimum requirements:
- Have a primary key.
 - A uniquely constrained identity field (eg 
usernameoremail) - 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_or_email, token, _opts ->
          # will be a user if the token relates to an existing user
          # will be an email if there is no matching user (such as during sign up)
          # opts will contain the `tenant` key, use this if you need to alter the link based
          # on the tenant that requested the token
          MyApp.Emails.deliver_magic_link(user_or_email, token)
        end
      end
    end
  end
  identities do
    identity :unique_email, [:email]
  end
endTenancy
Note that the tenant is provided to the sender in the opts key. Use this if you need
to modify the url (i.e tenant.app.com) based on the tenant that requested the token.
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})
:okSigning 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
trueUsage with AshAuthenticationPhoenix
If you are using AshAuthenticationPhoenix, and have require_authentication? set to true, which you very much should, then you will need to add a magic_sign_in_route to your router. This is placed in the same location as auth_routes, and should be provided the user and the strategy name. For example:
# Remove this if you do not want to use the magic link strategy
magic_sign_in_route(
  MyApp.Accounts.User,
  :sign_in,
  auth_routes_prefix: "/auth",
  overrides: [MyApp.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default]
)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
trueSee the Magic Link Tutorial for more information.
authentication.strategies.magic_link
magic_link name \\ :magic_linkStrategy for authenticating using local users with a magic link
Options
| Name | Type | Default | Docs | 
|---|---|---|---|
sender | (any, any, any -> any) | module | How to send the magic link to the user. | |
identity_field | atom | :username | The name of the attribute which uniquely identifies the user, usually something like username or email_address. | 
token_lifetime | pos_integer | {pos_integer, :days | :hours | :minutes | :seconds} | {10, :minutes} | How long the sign in token is valid.  If no unit is provided, then minutes is assumed. | 
prevent_hijacking? | boolean | true | Requires a confirmation add_on to be present if the password strategy is used with the same identity_field. | 
require_interaction? | boolean | false | Whether or not to require user interaction to sign in. If true, the magic link URLs are changed to a POST request, and AshAuthenticationPhoenix will show a button to confirm when the page is visited | 
request_action_name | atom | The name to use for the request action. Defaults to request_<strategy_name> | |
lookup_action_name | atom | The action to use when looking up a user by their identity. Defaults to get_by_<identity_field> | |
single_use_token? | boolean | true | Automatically revoke the token once it's been used for sign in. | 
registration_enabled? | boolean | Allows registering via magic link. Signing in with magic link becomes an upsert action instead of a read action. | |
sign_in_action_name | atom | The name to use for the sign in action. Defaults to sign_in_with_<strategy_name> | |
token_param_name | atom | :token | The name of the token parameter in the incoming sign-in request. |