sezaru

sezaru

My user resource thas the following relationship:

    many_to_many :schools, School do
      through UserSchool
      join_relationship :user_schools

      source_attribute_on_join_resource :user_id
      destination_attribute_on_join_resource :school_id
    end

In my School resource, I have the following policy:

  policies do
    alias School.Checks

    policy always() do
      authorize_if Checks.IsConfirmed
    end
  end

And the IsConfirmed check is implemented as this:

defmodule Core.Ash.Checks.IsConfirmed do
  @moduledoc false

  use Ash.Policy.SimpleCheck

  def describe(_), do: "actor account is confirmed"

  def match?(%{confirmed_at: nil}, _, _), do: false
  def match?(%{confirmed_at: _}, _, _), do: true
end

After upgrading to Ash 3.0, when I try to sign-in using the sign_in_with_password action, the actor field from match?/3 always arrive as nil which will fail the match of the check.

Did something changed that I need to update to make this work again? I check both Ash upgrade guide and Ash authentication one but didn’t find anything that would help.

Showing Posts 1 to 10

zachdaniel

zachdaniel

Creator of Ash

Hm…the actor is never set when calling sign_in_with_password AFAIK. It’s not set because we don’t know who it is yet, because the user isn’t authenticated. Are you saying this is happening in the :sign_in_with_password action? Or is this perhaps happening elsewhere?

Actually, I bet I know what changed :slight_smile: The default for authorize? is now true (see the upgrade guide for more on that). Either

  1. you have an action where you need to pass authorize?: false
  2. you need to add the ash authentication bypass. This should be documented in the ash_authentication getting started guide.
sezaru

sezaru OP

Hmm, shouldn’t authorize? be false when calling the sign_in_with_password action since, as you correctly said, there is no actor?

I could change it to false manually, but that would apply to every call the School.read action correctly?

What I would prefer is to know if the parent action is a ash_authentication action and handle that accordingly in my policy, but looking at the context, I couldn’t find anything that indicates that the sign_in_with_password action was called.

I also tried to add the ash_authentication bypass rule to School but that doesn’t seem to work either.

Any idea on how I can achieve this? Otherwise I think I will just have to create a match? case where if actor is nil it will authorize, but that doesn’t seem very secure.

zachdaniel

zachdaniel

Creator of Ash

authorize? will be true when calling sign_in_with_password. It’s not sufficient to know that a given action is an action added by ash authentication, because ash authentication isn’t the only thing capable of calling it.

When you say “parent action”. Definitely don’t create a match allowing a non-logged in user to do the action you’re writing.

I think the missing context here is that you haven’t explained yet exactly what is being called and from where. It’s reasonable to hook into the actions you’re hooking into, but how are you doing it? What is triggering a read of School when a user signs in?

sezaru

sezaru OP

Ah, sorry if I was not clear.

The School.read action is being called by this many_to_many relationship:

    many_to_many :schools, School do
      through UserSchool
      join_relationship :user_schools

      source_attribute_on_join_resource :user_id
      destination_attribute_on_join_resource :school_id
    end

So, basically, when I run the sign_in_with_password action, the :school relationship will be loaded by default which will call School.read action and will call my IsConfirmed check.

zachdaniel

zachdaniel

Creator of Ash

How are you accomplishing the loading by default? A global preparation?

sezaru

sezaru OP

Yep, like this:

  preparations do
    prepare build(
              load: [
                :full_name,
                :subscription,
                user_schools: [:school],
                user_organizations: [:organization]
              ]
            )
  end
zachdaniel

zachdaniel

Creator of Ash

Gotcha. :thinking:. Do you need those loaded on the registration action?

sezaru

sezaru OP

So, I use these loads to handle next steps after an user signs-in (or register). For example, I will check the subscription relationship to see if there a plan already active. Or I will check if the school page I’m in right now is one that the user should have access (checking the schools relationship), etc.

i guess I could split this into a manual Ash.load function call after the user sign-in, but in that case I would need to be very careful to always add these whenever I’m updating the user.

If that is the correct/better way to handle it, I will do it, but at the same time I was wondering if there is workarounds :slight_smile:

zachdaniel

zachdaniel

Creator of Ash

There are workarounds, yes :slight_smile:

Something like this might do it?

prepare fn query, _ -> 
  load_statement = [...]
  if query.action.name == :sign_in_with_password do
    Ash.Query.after_action(query, fn query, [user] = results -> 
      Ash.load(query, load_statement, actor: user)

      query, results ->
        # I don't actually think you need to do this, but `ash_authentication`
        # would translate the "multiple users matching" scenario into an error
        # so if you get more than one result you can ignore it
        {:ok, results}
    end)
  else
    Ash.Query.load(query, load_statement)
  end
end
sezaru

sezaru OP

Shouldn’t Ash.load(query, load_statement, actor: user) be Ash.load(user, load_statement, actor: user) and Ash.Query.load(query, load_statement) be Ash.Query.load(user, load_statement)?

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews