A title for your blog

Learning Elixir, Phoenix and Ash Part 5: Authentication

Ash comes with a utility library called Ash Authentication. This adds authentication to your Ash app similar to the way something like Devise does in Ruby on Rails.

This comes with a generator that gives you options to allow a bunch of authentication mechanisms (strategies), eg password, magic link, oauth, etc. I chose password and with that I also got token authentication. The generator set up the domain, Accounts, and a couple of resources, User and Token. It also created a view in lib/my_app_web/controllers/page_html/home.html.heex that gives you a header with login-out and signup buttons.

The first thing I did was move this default view to the app layout (lib/my_app_web/components/layouts/app.html.heex). This seemed like a better place for it as I am going to be using LiveView for all the views. The generator made a controller too which I’m not going to change for now. I know live view doesn’t use controllers but it works so I’ll leave it until later.

The default User resource comes with what looks like a lot of useful actions. Eg.

read :get_by_email do

The only problem is you can’t call any of them. This is because the User has a couple of policies set which by default disallows calling any of the actions. The default policies look like this

  # You can customize this if you wish, but this is a safe default that
  # only allows user data to be interacted with via AshAuthentication.
  policies do
    bypass AshAuthentication.Checks.AshAuthenticationInteraction do
      authorize_if always()
    end

    policy always() do
      forbid_if always()
    end
  end

This had me confused for a while because I was able to signup and login using the view and controller so the actions can be called somehow.

This is made possible by this piece of code which, as the name suggests, sets up a bypass for the AshAuthenticationInteraction

bypass AshAuthentication.Checks.AshAuthenticationInteraction do
  authorize_if always()
end

This basically says allow code in the AshAunthentication library to bypass the policies.

So if you need to call the actions the first thing you need to do is add your own policies

policies do
  bypass AshAuthentication.Checks.AshAuthenticationInteraction do
    authorize_if always()
  end

  policy action(:register_with_password) do
    authorize_if always()
  end

  policy action(:get_by_email) do
    authorize_if always()
  end
end

I gave myself access toregister_with_password and get_by_email so I could set up User resources in the tests. I haven’t used them for anything else yet so it’s possible I should be doing something different in my tests.

I have signup, login and logout working. Once I figured out what was going with the policies it was pretty easy to get working. Ash Authentication is a nice library (or whatever they’re called in Elixir). It’s much simpler than Devise which is a good thing IMO. It reminds me more of the authentication zero gem which I’ve started using for my Rails apps.

I’m going to try some of the other strategies later on.

#ash #elixir #phoenix