View Source AshAuthentication (ash_authentication v3.5.0)

AshAuthentication provides a turn-key authentication solution for folks using Ash.

usage

Usage

This package assumes that you have Ash installed and configured. See the Ash documentation for details.

Once installed you can easily add support for authentication by configuring the AshAuthentication extension on your resource:

defmodule MyApp.Accounts.User do
  use Ash.Resource,
    extensions: [AshAuthentication]

  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
    api MyApp.Accounts

    strategies do
      password :password do
        identity_field :email
        hashed_password_field :hashed_password
      end
    end
  end

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

If you plan on providing authentication via the web, then you will need to define a plug using AshAuthentication.Plug which builds a Plug.Router that routes incoming authentication requests to the correct provider and provides callbacks for you to manipulate the conn after success or failure.

If you're using AshAuthentication with Phoenix, then check out ash_authentication_phoenix which provides route helpers, a controller abstraction and LiveView components for easy set up.

authentication-strategies

Authentication Strategies

Currently supported strategies:

  1. AshAuthentication.Strategy.Password
    • authenticate users against your local database using a unique identity (such as username or email address) and a password.
  2. AshAuthentication.Strategy.OAuth2
    • authenticate using local or remote OAuth 2.0 compatible services.

add-ons

Add-ons

Add-ons are like strategies, except that they don't actually provide authentication - they just provide features adjacent to authentication. Current add-ons:

  1. AshAuthentication.AddOn.Confirmation
    • allows you to force the user to confirm changes using a confirmation token (eg. sending a confirmation email when a new user registers).

supervisor

Supervisor

Some add-ons or strategies may require processes to be started which manage their state over the lifetime of the application (eg periodically deleting expired token revocations). Because of this you should add {AshAuthentication.Supervisor, otp_app: :my_app} to your application's supervision tree. See the Elixir docs for more information.

dsl-documentation

DSL Documentation

index

Index

  • authentication
    • tokens
    • strategies
      • password
        • resettable
      • oauth2
      • auth0
      • github
    • add_ons
      • confirmation

docs

Docs

authentication

authentication

Configure authentication for this resource


  • :subject_name (atom/0) - The subject name is used anywhere that a short version of your resource name is needed, eg:

    • generating token claims,
    • generating routes,
    • form parameter nesting.
      This needs to be unique system-wide and if not set will be inferred from the resource name (ie MyApp.Accounts.User will have a subject name of user).
  • :api (atom/0) - Required. The name of the Ash API to use to access this resource when doing anything authenticaiton related.

  • :get_by_subject_action_name (atom/0) - The name of the read action used to retrieve records.
    Used internally by AshAuthentication.subject_to_user/2. If the action doesn't exist, one will be generated for you. The default value is :get_by_subject.

tokens

tokens

Configure JWT settings for this resource


  • :enabled? (boolean/0) - Should JWTs be generated by this resource? The default value is false.

  • :store_all_tokens? (boolean/0) - Store all tokens in the token_resource?
    Some applications need to keep track of all tokens issued to any user. This is optional behaviour with ash_authentication in order to preserve as much performance as possible. The default value is false.

  • :require_token_presence_for_authentication? (boolean/0) - Require a locally-stored token for authentication?
    This inverts the token validation behaviour from requiring that tokens are not revoked to requiring any token presented by a client to be present in the token resource to be considered valid.
    Requires store_all_tokens? to be true. The default value is false.

  • :signing_algorithm (String.t/0) - The algorithm to use for token signing.
    Available signing algorithms are; Ed448ph, Ed448, Ed25519ph, Ed25519, PS512, PS384, PS256, ES512, ES384, ES256, RS512, RS384, RS256, HS512, HS384 and HS256. The default value is "HS256".

  • :token_lifetime (pos_integer/0) - How long a token should be valid, in hours.
    Since refresh tokens are not yet supported, you should probably set this to a reasonably long time to ensure a good user experience.
    Defaults to 14 days. The default value is 336.

  • :token_resource - Required. The resource used to store token information.
    If token generation is enabled for this resource, we need a place to store information about tokens, such as revocations and in-flight confirmations.

  • :signing_secret - The secret used to sign tokens.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

strategies

strategies

Configure authentication strategies on this resource


password

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
  • :identity_field (atom/0) - The name of the attribute which uniquely identifies the user.
    Usually something like username or email_address. The default value is :username.

  • :hashed_password_field (atom/0) - The name of the attribute within which to store the user's password once it has been hashed. The default value is :hashed_password.

  • :hash_provider (atom/0) - A module which implements the AshAuthentication.HashProvider behaviour.
    Used to provide cryptographic hashing of passwords. The default value is AshAuthentication.BcryptProvider.

  • :confirmation_required? (boolean/0) - Whether a password confirmation field is required when registering or changing passwords. The default value is true.

  • :password_field (atom/0) - The name of the argument used to collect the user's password in plaintext when registering, checking or changing passwords. The default value is :password.

  • :password_confirmation_field (atom/0) - The name of the argument used to confirm the user's password in plaintext when registering or changing passwords. The default value is :password_confirmation.

  • :register_action_name (atom/0) - The name to use for the register action.
    If not present it will be generated by prepending the strategy name with register_with_.

  • :sign_in_action_name (atom/0) - 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_.

resettable

Configure password reset options for the resource

  • :token_lifetime (pos_integer/0) - How long should the reset token be valid, in hours.
    Defaults to 3 days. The default value is 72.

  • :request_password_reset_action_name (atom/0) - 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_.

  • :password_reset_action_name (atom/0) - 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_.

  • :sender - Required. How to send the password reset instructions to the user.
    Allows you to glue sending of reset instructions to swoosh, 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.

oauth2

OAuth2 authentication

  • :client_id - Required. The OAuth2 client ID.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    client_id fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_client_id)
    end
  • :site - Required. The base URL of the OAuth2 server - including the leading protocol (ie https://).
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    site fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_site)
    end
  • :auth_method - The authentication strategy used, optional. If not set, no authentication will be used during the access token request. The value may be one of the following:

    • :client_secret_basic
    • :client_secret_post
    • :client_secret_jwt
    • :private_key_jwt The default value is :client_secret_post.
  • :client_secret - The OAuth2 client secret.
    Required if :auth_method is :client_secret_basic, :client_secret_post or :client_secret_jwt.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    site fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_site)
    end
  • :authorize_url - Required. The API url to the OAuth2 authorize endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    authorize_url fn _, _ -> {:ok, "https://exampe.com/authorize"} end
  • :token_url - Required. The API url to access the token endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    token_url fn _, _ -> {:ok, "https://example.com/oauth_token"} end
  • :user_url - Required. The API url to access the user endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    user_url fn _, _ -> {:ok, "https://example.com/userinfo"} end
  • :private_key - The private key to use if :auth_method is :private_key_jwt
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

  • :redirect_uri - Required. The callback URI base.
    Not the whole URI back to the callback endpoint, but the URI to your AuthPlug. We can generate the rest.
    Whilst not particularly secret, it seemed prudent to allow this to be configured dynamically so that you can use different URIs for different environments.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

  • :authorization_params (keyword/0) - Any additional parameters to encode in the request phase.
    eg: authorization_params scope: "openid profile email" The default value is [].

  • :registration_enabled? (boolean/0) - Is registration enabled for this provider?
    If this option is enabled, then new users will be able to register for your site when authenticating and not already present.
    If not, then only existing users will be able to authenticate. The default value is true.

  • :register_action_name (atom/0) - The name of the action to use to register a user.
    Only needed if registration_enabled? is true.
    Because we we don't know the response format of the server, you must implement your own registration action of the same name.
    See the "Registration and Sign-in" section of the module documentation for more information.
    The default is computed from the strategy name eg: register_with_#{name}.

  • :sign_in_action_name (atom/0) - The name of the action to use to sign in an existing user.
    Only needed if registration_enabled? is false.
    Because we don't know the response format of the server, you must implement your own sign-in action of the same name.
    See the "Registration and Sign-in" section of the module documentation for more information.
    The default is computed from the strategy name, eg: sign_in_with_#{name}.

  • :identity_resource - The resource used to store user identities.
    Given that a user can be signed into multiple different authentication providers at once we use the AshAuthentication.UserIdentity resource to build a mapping between users, providers and that provider's uid.
    See the Identities section of the module documentation for more information.
    Set to false to disable. The default value is false.

  • :identity_relationship_name (atom/0) - Name of the relationship to the provider identities resource The default value is :identities.

  • :identity_relationship_user_id_attribute (atom/0) - The name of the destination (user_id) attribute on your provider identity resource.
    The only reason to change this would be if you changed the user_id_attribute_name option of the provider identity. The default value is :user_id.

  • :name (atom/0) - Required. Uniquely identifies the strategy.

auth0

Auth0 authentication

  • :client_id - Required. The OAuth2 client ID.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    client_id fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_client_id)
    end
  • :site - Required. The base URL of the OAuth2 server - including the leading protocol (ie https://).
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    site fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_site)
    end
  • :auth_method - The authentication strategy used, optional. If not set, no authentication will be used during the access token request. The value may be one of the following:

    • :client_secret_basic
    • :client_secret_post
    • :client_secret_jwt
    • :private_key_jwt The default value is :client_secret_post.
  • :client_secret - The OAuth2 client secret.
    Required if :auth_method is :client_secret_basic, :client_secret_post or :client_secret_jwt.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    site fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_site)
    end
  • :authorize_url - Required. The API url to the OAuth2 authorize endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    authorize_url fn _, _ -> {:ok, "https://exampe.com/authorize"} end
  • :token_url - Required. The API url to access the token endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    token_url fn _, _ -> {:ok, "https://example.com/oauth_token"} end
  • :user_url - Required. The API url to access the user endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    user_url fn _, _ -> {:ok, "https://example.com/userinfo"} end
  • :private_key - The private key to use if :auth_method is :private_key_jwt
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

  • :redirect_uri - Required. The callback URI base.
    Not the whole URI back to the callback endpoint, but the URI to your AuthPlug. We can generate the rest.
    Whilst not particularly secret, it seemed prudent to allow this to be configured dynamically so that you can use different URIs for different environments.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

  • :authorization_params (keyword/0) - Any additional parameters to encode in the request phase.
    eg: authorization_params scope: "openid profile email" The default value is [].

  • :registration_enabled? (boolean/0) - Is registration enabled for this provider?
    If this option is enabled, then new users will be able to register for your site when authenticating and not already present.
    If not, then only existing users will be able to authenticate. The default value is true.

  • :register_action_name (atom/0) - The name of the action to use to register a user.
    Only needed if registration_enabled? is true.
    Because we we don't know the response format of the server, you must implement your own registration action of the same name.
    See the "Registration and Sign-in" section of the module documentation for more information.
    The default is computed from the strategy name eg: register_with_#{name}.

  • :sign_in_action_name (atom/0) - The name of the action to use to sign in an existing user.
    Only needed if registration_enabled? is false.
    Because we don't know the response format of the server, you must implement your own sign-in action of the same name.
    See the "Registration and Sign-in" section of the module documentation for more information.
    The default is computed from the strategy name, eg: sign_in_with_#{name}.

  • :identity_resource - The resource used to store user identities.
    Given that a user can be signed into multiple different authentication providers at once we use the AshAuthentication.UserIdentity resource to build a mapping between users, providers and that provider's uid.
    See the Identities section of the module documentation for more information.
    Set to false to disable. The default value is false.

  • :identity_relationship_name (atom/0) - Name of the relationship to the provider identities resource The default value is :identities.

  • :identity_relationship_user_id_attribute (atom/0) - The name of the destination (user_id) attribute on your provider identity resource.
    The only reason to change this would be if you changed the user_id_attribute_name option of the provider identity. The default value is :user_id.

  • :name (atom/0) - Required. Uniquely identifies the strategy.

github

GitHub authentication

  • :client_id - Required. The OAuth2 client ID.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    client_id fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_client_id)
    end
  • :site - Required. The base URL of the OAuth2 server - including the leading protocol (ie https://).
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    site fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_site)
    end
  • :auth_method - The authentication strategy used, optional. If not set, no authentication will be used during the access token request. The value may be one of the following:

    • :client_secret_basic
    • :client_secret_post
    • :client_secret_jwt
    • :private_key_jwt The default value is :client_secret_post.
  • :client_secret - The OAuth2 client secret.
    Required if :auth_method is :client_secret_basic, :client_secret_post or :client_secret_jwt.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    site fn _, resource ->
      :my_app
      |> Application.get_env(resource, [])
      |> Keyword.fetch(:oauth_site)
    end
  • :authorize_url - Required. The API url to the OAuth2 authorize endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    authorize_url fn _, _ -> {:ok, "https://exampe.com/authorize"} end
  • :token_url - Required. The API url to access the token endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    token_url fn _, _ -> {:ok, "https://example.com/oauth_token"} end
  • :user_url - Required. The API url to access the user endpoint.
    Relative to the value of site.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

    Example:

    user_url fn _, _ -> {:ok, "https://example.com/userinfo"} end
  • :private_key - The private key to use if :auth_method is :private_key_jwt
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

  • :redirect_uri - Required. The callback URI base.
    Not the whole URI back to the callback endpoint, but the URI to your AuthPlug. We can generate the rest.
    Whilst not particularly secret, it seemed prudent to allow this to be configured dynamically so that you can use different URIs for different environments.
    Takes either a module which implements the AshAuthentication.Secret behaviour, a 2 arity anonymous function or a string.
    See the module documentation for AshAuthentication.Secret for more information.

  • :authorization_params (keyword/0) - Any additional parameters to encode in the request phase.
    eg: authorization_params scope: "openid profile email" The default value is [].

  • :registration_enabled? (boolean/0) - Is registration enabled for this provider?
    If this option is enabled, then new users will be able to register for your site when authenticating and not already present.
    If not, then only existing users will be able to authenticate. The default value is true.

  • :register_action_name (atom/0) - The name of the action to use to register a user.
    Only needed if registration_enabled? is true.
    Because we we don't know the response format of the server, you must implement your own registration action of the same name.
    See the "Registration and Sign-in" section of the module documentation for more information.
    The default is computed from the strategy name eg: register_with_#{name}.

  • :sign_in_action_name (atom/0) - The name of the action to use to sign in an existing user.
    Only needed if registration_enabled? is false.
    Because we don't know the response format of the server, you must implement your own sign-in action of the same name.
    See the "Registration and Sign-in" section of the module documentation for more information.
    The default is computed from the strategy name, eg: sign_in_with_#{name}.

  • :identity_resource - The resource used to store user identities.
    Given that a user can be signed into multiple different authentication providers at once we use the AshAuthentication.UserIdentity resource to build a mapping between users, providers and that provider's uid.
    See the Identities section of the module documentation for more information.
    Set to false to disable. The default value is false.

  • :identity_relationship_name (atom/0) - Name of the relationship to the provider identities resource The default value is :identities.

  • :identity_relationship_user_id_attribute (atom/0) - The name of the destination (user_id) attribute on your provider identity resource.
    The only reason to change this would be if you changed the user_id_attribute_name option of the provider identity. The default value is :user_id.

  • :name (atom/0) - Required. Uniquely identifies the strategy.

add_ons

add_ons

Additional add-ons related to, but not providing authentication


confirmation

User confirmation flow

  • :token_lifetime (pos_integer/0) - How long should the confirmation token be valid, in hours.
    Defaults to 3 days. The default value is 72.

  • :monitor_fields (list of atom/0) - Required. A list of fields to monitor for changes (eg [:email, :phone_number]).
    The confirmation will only be sent when one of these fields are changed.

  • :confirmed_at_field (atom/0) - The name of a field to store the time that the last confirmation took place.
    This attribute will be dynamically added to the resource if not already present. The default value is :confirmed_at.

  • :confirm_on_create? (boolean/0) - Generate and send a confirmation token when a new resource is created?
    Will only trigger when a create action is executed and one of the monitored fields is being set. The default value is true.

  • :confirm_on_update? (boolean/0) - Generate and send a confirmation token when a resource is changed?
    Will only trigger when an update action is executed and one of the monitored fields is being set. The default value is true.

  • :inhibit_updates? (boolean/0) - Wait until confirmation is received before actually changing a monitored field?
    If a change to a monitored field is detected, then the change is stored in the token resource and the changeset updated to not make the requested change. When the token is confirmed, the change will be applied.
    This could be potentially weird for your users, but useful in the case of a user changing their email address or phone number where you want to verify that the new contact details are reachable. The default value is true.

  • :sender - Required. How to send the confirmation instructions to the user.
    Allows you to glue sending of confirmation instructions to swoosh, 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.

  • :confirm_action_name (atom/0) - The name of the action to use when performing confirmation.
    If this action is not already present on the resource, it will be created for you. The default value is :confirm.

  • :name (atom/0) - Required. Uniquely identifies the add-on.

Link to this section Summary

Functions

Find all resources which support authentication for a given OTP application.

Given a subject string, attempt to retrieve a user record.

Return a subject string for user.

Link to this section Types

@type resource_config() :: %{
  api: module(),
  providers: [module()],
  resource: module(),
  subject_name: atom()
}
@type subject() :: String.t()

Link to this section Functions

Link to this function

authenticated_resources(otp_app)

View Source
@spec authenticated_resources(atom()) :: [Ash.Resource.t()]

Find all resources which support authentication for a given OTP application.

Returns a list of resource modules.

example

Example

iex> authenticated_resources(:ash_authentication)
[Example.User, Example.UserWithTokenRequired]
Link to this function

subject_to_user(subject, resource, options \\ [])

View Source
@spec subject_to_user(subject() | URI.t(), Ash.Resource.t(), keyword()) ::
  {:ok, Ash.Resource.record()} | {:error, any()}

Given a subject string, attempt to retrieve a user record.

iex> %{id: user_id} = build_user()
...> {:ok, %{id: ^user_id}} = subject_to_user("user?id=#{user_id}", Example.User)

Any options passed will be passed to the underlying Api.read/2 callback.

@spec user_to_subject(Ash.Resource.record()) :: subject()

Return a subject string for user.

This is done by concatenating the resource's subject name with the resource's primary key field(s) to generate a uri-like string.

Example:

iex> build_user(id: "ce7969f9-afa5-474c-bc52-ac23a103cef6") |> user_to_subject()
"user?id=ce7969f9-afa5-474c-bc52-ac23a103cef6"