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.