Configuration

View Source

This guide covers all configuration options available in Usher and how to set them up for different scenarios.

Basic Configuration

Configure Usher in your config/config.exs file:

config :usher,
  repo: MyApp.Repo,
  token_length: 16,
  default_expires_in: {7, :day},
  validations: %{
    invitation: %{
      name_required: true
    },
    invitation_usage: %{
      valid_usage_entity_types: [:user, :company, :device],
      valid_usage_actions: [:visited, :registered, :activated]
    }
  },
  signing_secret: System.fetch_env!("USHER_SIGNING_SECRET")

Configuration Options

OptionTypeDefaultRequiredDescription
:repomoduleN/AYesYour Ecto repository module
:token_lengthinteger16NoLength of generated invitation tokens
:default_expires_intuple{7, :day}NoDefault expiration period for new invitations
:validationsmap%{}NoMap defining validation rules for invitations
:schemasmap%{}NoMap defining custom schema configurations
:signing_secretstringnilOnly when using signed tokensSecret used to sign/verify user-supplied tokens

Validations

You can define validation rules for invitations using the :validations option. This allows you to enforce (or make optional) certain rules (available as features in Usher) such as requiring a name for invitations.

The :validations option accepts a map where keys are schema types (like :invitation) and values are maps of validation rules. For example:

config :usher,
  validations: %{
    invitation: %{
      name_required: false
    },
    invitation_usage: %{
      valid_usage_entity_types: [:user, :company, :device],
      valid_usage_actions: [:visited, :registered, :activated]
    }
  }

The available options for :invitation are:

OptionTypeDefaultRequiredDescription
:name_requiredbooleantrueNoWhether the invitation must have a name

The available options for :invitation_usage are:

OptionTypeDefaultRequiredDescription
:valid_usage_entity_typeslistnilYesList of atoms defining allowed entity types for usage tracking
:valid_usage_actionslistnilYesList of atoms defining allowed actions for usage tracking

Schemas

You can customize the schema behavior for various parts of Usher using the :schema_overrides option.

The :schema_overrides option accepts a map where keys are schema names (like :invitation) and values are maps of schema configurations. For example:

config :usher,
  schema_overrides: %{
    invitation: %{
      custom_attributes_type: MyApp.InvitationAttributes
    }
  }

The available options for :invitation schemas are:

OptionTypeDefaultRequiredDescription
:custom_attributes_typemodule:mapNoEmbedded schema module for custom_attributes field. If not defined, defaults to :map

Invitation :custom_attributes Configuration

Usher supports storing custom attributes with invitations through the custom_attributes field. By default, this field uses the :map type. If you want better type safety and validations, you can use an embedded schema.

Using Map Type (Default)

When :custom_attributes_type is not defined, the value of invitation.custom_attributes will be of type Map:

{:ok, invitation} = Usher.create_invitation(%{
  name: "Join our team",
  custom_attributes: %{
    role: "developer",
    department: "engineering",
    tags: ["backend", "elixir"]
  }
})

# Access after validation
case Usher.validate_invitation_token(token) do
  {:ok, invitation} ->
    role = invitation.custom_attributes.role
    # Use role for user creation or other business logic
  {:error, reason} ->
    # Handle error
end

Using Embedded Schema

For better type safety and validation, you can set :custom_attributes_type to an embedded schema:

# In config/config.exs
config :usher,
  repo: MyApp.Repo,
  # Other configuration...
  schema_overrides: %{
    invitation: %{
      custom_attributes_type: MyApp.InvitationAttributes
    }
  }

Then define your embedded schema:

defmodule MyApp.InvitationAttributes do
  use Ecto.Schema
  import Ecto.Changeset

  @primary_key false

  embedded_schema do
    field(:role, Ecto.Enum, values: [:admin, :manager, :user])
    field(:department, :string)
    field(:tags, {:array, :string})
    field(:welcome_message, :string)
  end

  def changeset(schema, attrs) do
    schema
    |> cast(attrs, [:role, :department, :tags, :welcome_message])
    |> validate_required([:role])
    |> validate_inclusion(:role, [:admin, :manager, :user])
  end
end

With the embedded schema configured, you can use it like this:

{:ok, invitation} = Usher.create_invitation(%{
  name: "Join our team",
  custom_attributes: %{
    role: :developer,
    department: "engineering",
    tags: ["backend", "elixir"],
    welcome_message: "Welcome to our development team!"
  }
})

# Access typed fields after validation
case Usher.validate_invitation_token(token) do
  {:ok, %{custom_attributes: %MyApp.InvitationAttributes{} = custom_attributes}} ->
    role = custom_attributes.role
    department = custom_attributes.department
    # Use role for user creation or other business logic
  {:error, reason} ->
    # Handle error
end

Entity Usage Tracking Configuration

For usage tracking of invitation interactions, you must configure entity types and actions:

config :usher,
  repo: MyApp.Repo,
  # Basic configuration
  token_length: 16,
  default_expires_in: {7, :day},
  # Entity tracking configuration
  validations: %{
    invitation_usage: %{
      valid_usage_entity_types: [:user, :company, :device],
      valid_usage_actions: [:visited, :registered, :activated]
    }
  }

Time Units

The :default_expires_in option accepts tuples with these time units:

  • :second
  • :minute
  • :hour
  • :day
  • :week
  • :month
  • :year

Examples:

# Various time configurations
default_expires_in: {30, :minute}   # 30 minutes
default_expires_in: {2, :hour}      # 2 hours
default_expires_in: {7, :day}       # 7 days (default)
default_expires_in: {2, :week}      # 2 weeks
default_expires_in: {1, :month}     # 1 month

Runtime Configuration

You can also configure Usher at runtime or override specific values:

# Override default expiration for specific invitations
{:ok, invitation} = Usher.create_invitation(%{
  expires_at: DateTime.add(DateTime.utc_now(), 1, :hour)
})

# Use custom token length (though token_length config is for generated tokens)
{:ok, invitation} = Usher.create_invitation(%{
  token: "my-very-long-custom-token-here"
})

# Signed token setup (requires signing_secret)
config :usher, signing_secret: System.fetch_env!("USHER_SIGNING_SECRET")

Accessing Configuration

You can access the current configuration in your application using the Usher.Config module.