lib/ash_authentication/strategies/password/dsl.ex

defmodule AshAuthentication.Strategy.Password.Dsl do
  @moduledoc """
  Defines the Spark DSL entity for this strategy.
  """

  alias AshAuthentication.Strategy.Password
  alias Spark.Dsl.Entity

  @default_token_lifetime_days 3

  @doc false
  @spec dsl :: map
  def dsl do
    %Entity{
      name: :password,
      describe: "Strategy for authenticating using local resources as the source of truth.",
      examples: [
        """
        password :password do
          identity_field :email
          hashed_password_field :hashed_password
          hash_provider AshAuthentication.BcryptProvider
          confirmation_required? true
        end
        """
      ],
      args: [{:optional, :name, :password}],
      hide: [:name],
      target: Password,
      modules: [:hash_provider],
      schema: [
        name: [
          type: :atom,
          doc: """
          Uniquely identifies the strategy.
          """,
          required: true
        ],
        identity_field: [
          type: :atom,
          doc: """
          The name of the attribute which uniquely identifies the user.

          Usually something like `username` or `email_address`.
          """,
          default: :username
        ],
        hashed_password_field: [
          type: :atom,
          doc: """
          The name of the attribute within which to store the user's password
          once it has been hashed.
          """,
          default: :hashed_password
        ],
        hash_provider: [
          type: {:behaviour, AshAuthentication.HashProvider},
          doc: """
          A module which implements the `AshAuthentication.HashProvider`
          behaviour.

          Used to provide cryptographic hashing of passwords.
          """,
          default: AshAuthentication.BcryptProvider
        ],
        confirmation_required?: [
          type: :boolean,
          required: false,
          doc: """
          Whether a password confirmation field is required when registering or
          changing passwords.
          """,
          default: true
        ],
        password_field: [
          type: :atom,
          doc: """
          The name of the argument used to collect the user's password in
          plaintext when registering, checking or changing passwords.
          """,
          default: :password
        ],
        password_confirmation_field: [
          type: :atom,
          doc: """
          The name of the argument used to confirm the user's password in
          plaintext when registering or changing passwords.
          """,
          default: :password_confirmation
        ],
        register_action_name: [
          type: :atom,
          doc: """
          The name to use for the register action.

          If not present it will be generated by prepending the strategy name
          with `register_with_`.
          """,
          required: false
        ],
        sign_in_action_name: [
          type: :atom,
          doc: """
          The name to use for the sign in action.

          If not present it will be generated by prependign the strategy name
          with `sign_in_with_`.
          """,
          required: false
        ]
      ],
      entities: [
        resettable: [
          %Entity{
            name: :resettable,
            describe: "Configure password reset options for the resource",
            target: Password.Resettable,
            schema: [
              token_lifetime: [
                type: :pos_integer,
                doc: """
                How long should the reset token be valid, in hours.

                Defaults to #{@default_token_lifetime_days} days.
                """,
                default: @default_token_lifetime_days * 24
              ],
              request_password_reset_action_name: [
                type: :atom,
                doc: """
                The name to use for the action which generates a password reset token.

                If not present it will be generated by prepending the strategy name
                with `request_password_reset_with_`.
                """,
                required: false
              ],
              password_reset_action_name: [
                type: :atom,
                doc: """
                The name to use for the action which actually resets the user's
                password.

                If not present it will be generated by prepending the strategy name
                with `password_reset_with_`.
                """,
                required: false
              ],
              sender: [
                type:
                  {:spark_function_behaviour, AshAuthentication.Sender,
                   {AshAuthentication.SenderFunction, 3}},
                doc: """
                How to send the password reset instructions to the user.

                Allows you to glue sending of reset instructions to [swoosh](https://hex.pm/packages/swoosh), [ex_twilio](https://hex.pm/packages/ex_twilio) or whatever notification system is appropriate for your application.

                Accepts a module, module and opts, or a function that takes a record, reset token and options.

                See `AshAuthentication.Sender` for more information.
                """,
                required: true
              ]
            ]
          }
        ]
      ]
    }
  end
end