Slack Tutorial
View SourceThis is a quick tutorial on how to configure your application to use Slack for authentication.
First you need to configure an application in your Slack app settings:
Click the "Create New App" button.
Select "From scratch"
Set your application name to something that identifies it. You will likely need separate applications for development and production environments, so keep that in mind.
Select a "development workspace", which can be used for testing.
Browse to the "OAuth & Permissions" page.
In the "Redirect URLs" section add your callback URL. The callback URL is generated from the following information:
- The base URL of the application - in development that would be
http://localhost:4000/but in production will be your application's URL. - The mount point of the auth routes in your router - we'll assume
/auth. - The "subject name" of the resource being authenticated - we'll assume 
user. - The name of the strategy in your configuration. By default this is
slack. 
This means that the callback URL should look something like
http://localhost:4000/auth/user/slack/callback.HTTPS Required
Slack won't allow you to register an HTTP URL as the redirect URL, so you will likely have to add a URL for a service like ngrok
- The base URL of the application - in development that would be
 In the "Scopes" section, add your user token scopes. You must request
openid, and may requestemailandprofileas well.In the "OAuth Tokens" section click "Install to :workspace:" where
:workspace:is the one you selected as the development workspace.Browse back to the "Basic Information".
Copy the "Client ID" and "Client secret" somewhere safe, we'll need them soon.
Next we can configure our resource (assuming you already have everything else set up):
defmodule MyApp.Accounts.User do
  use Ash.Resource,
    extensions: [AshAuthentication],
    domain: MyApp.Accounts
  authentication do
    strategies do
      slack do
        client_id MyApp.Secrets
        redirect_uri MyApp.Secrets
        client_secret MyApp.Secrets
      end
    end
  end
endBecause all the configuration values should be kept secret (ie the
client_secret) or are likely to be different for each environment we use the
AshAuthentication.Secret behaviour to provide them. In this case we're
delegating to the OTP application environment, however you may want to use a
system environment variable or some other secret store (eg Vault).
defmodule MyApp.Secrets do
  use AshAuthentication.Secret
  def secret_for([:authentication, :strategies, :slack, :client_id], MyApp.Accounts.User, _) do
    get_config(:client_id)
  end
  def secret_for([:authentication, :strategies, :slack, :redirect_uri], MyApp.Accounts.User, _) do
    get_config(:redirect_uri)
  end
  def secret_for([:authentication, :strategies, :slack, :client_secret], MyApp.Accounts.User, _) do
    get_config(:client_secret)
  end
  defp get_config(key) do
    :my_app
    |> Application.get_env(:slack, [])
    |> Keyword.fetch(key)
  end
endThe values for this configuration should be:
client_id- the client ID copied from the Slack settings page.redirect_uri- the URL to the generated auth routes in your application (eghttp://localhost:4000/auth).client_secretthe client secret copied from the Slack settings page.
Lastly, we need to add a register action to your user resource. This is defined
as an upsert so that it can register new users, or update information for
returning users. The default name of the action is register_with_ followed by
the strategy name. In our case that is register_with_slack.
The register action takes two arguments, user_info and the oauth_tokens.
user_infocontains theGET /userresponse from Slack which you can use to populate your user attributes as needed.oauth_tokenscontains thePOST /login/oauth/access_tokenresponse from Slack- you may want to store these if you intend to call the Slack API on behalf of the user.
 
defmodule MyApp.Accounts.User do
  require Ash.Resource.Change.Builtins
  use Ash.Resource,
    extensions: [AshAuthentication],
    domain: MyApp.Accounts
  # ...
  actions do
    create :register_with_slack do
      argument :user_info, :map, allow_nil?: false
      argument :oauth_tokens, :map, allow_nil?: false
      upsert? true
      upsert_identity :unique_email
      # Required if you have token generation enabled.
      change AshAuthentication.GenerateTokenChange
      # Required if you have the `identity_resource` configuration enabled.
      change AshAuthentication.Strategy.OAuth2.IdentityChange
      change fn changeset, _ ->
        user_info = Ash.Changeset.get_argument(changeset, :user_info)
        Ash.Changeset.change_attributes(changeset, Map.take(user_info, ["email"]))
      end
      # Required if you're using the password & confirmation strategies
      upsert_fields []
      change set_attribute(:confirmed_at, &DateTime.utc_now/0)
      change after_action(fn _changeset, user, _context ->
        case user.confirmed_at do
          nil -> {:error, "Unconfirmed user exists already"}
          _ -> {:ok, user}
        end
      end)
    end
  end
  # ...
endEnsure you set the hashed_password to allow_nil? if you are also using the password strategy.
defmodule MyApp.Accounts.User do
  # ...
  attributes do
    # ...
    attribute :hashed_password, :string, allow_nil?: true, sensitive?: true
  end
  # ...
endAnd generate and run migrations in that case.
mix ash.codegen make_hashed_password_nullable
mix ash.migrate