Ash authentication on mobile

Whats wrong with writing the custom check as you mentioned originally? Then you don’t have to do it in the controller. The general goal for building with Ash is to put as much of this stuff in the resource, to encapsulate the domain operation happening. Most people using Ash won’t even have controllers because they’ll use an api extension :slight_smile:

1 Like

Well with this:

    policy action_type(:read) do
      authorize_if(IsOwnerCheck)
    end

and this:

  defmodule IsOwnerCheck do
    use Ash.Policy.SimpleCheck

    def match?(actor, context, opts) do
      What.To.Do.here?
    end

    def describe(x) do
      x |> IO.inspect(label: ~S/x/)
      "hello"
    end
  end

I am not sure what I should do in the simple check. The context contains a query but If I run the query I get an infinite loop. I cannot use MyApi.can? because that would be an infinite loop as well.

I am not sure if I want the JSON API extension right now. I’all have two or three resources only but with some complicated logic in the backend, I do not feel like a REST API would be good for this. But I might try.

Ah, I was thinking you would want an Ash.Policy.Check instead of an Ash.Policy.SimpleCheck. But even then the check function has you manually filter down the results, like so:

  defmodule IsOwnerCheck do
    use Ash.Policy.SimpleCheck

    def describe(_x) do
      "actor is owner"
    end

    def strict_check(_, _, _) do
      :unknown
    end

    def check(_, records, _) do
      # return only the records that match
      Enum.filter(records, fn record -> 
        ...matches?
      end)
    end
  end

But that isn’t what you’d want in this case. I think we’d want to expand the policy options to allow you to do something like this as an “after” check, which doesn’t filter and can only forbid access. Barring that, I would suggest the after action hook that returns the forbidden error. Its hard for me to say looking at it why its not working for you, but I’ve got very similar setups in various places.

The simplest answer in your case to get you over the current hurdle would to just put the same logic you’d put in the controller in the after action hook, and skip the Api.can? step.

Ok so I got it working like you said by putting the logic in the “after”:

    read :by_id do
      argument(:id, :uuid, allow_nil?: false)
      get?(true)
      filter(expr(id == ^arg(:id)))

      prepare(fn query, %{actor: actor} ->
        Ash.Query.after_action(query, fn
          _, [] ->
            {:ok, []}

          _, [single] ->
            case single.owner_id == actor.id do
              true -> {:ok, [single]}
              false -> {:error, Ash.Error.Forbidden.exception([])}
            end
        end)
      end)
    end

Next step will be to look in the “allowances” table if there is a record for that inventory and that actor, to also allow :smiley:

Thank you for your help @zachdaniel !