Ash FrameworkAF
Ash Framework6mo ago
5 replies
Shahryar

Miss understanding to use policy in read action, Handling Missing Actor

Hi sorry again, I've read the documentation multiple times but still struggle to properly handle a case in my :me action.

Here’s my current setup:

read :me do
  description "Get the current authenticated user"
  get? true
  filter expr(id == ^actor(:id))
  prepare fn query, _context ->
    query
    |> Ash.Query.load([:permissions, :permission_values, :site])
  end
end

bypass action(:me) do
  authorize_if expr(id == ^actor(:id))
end


This works when a valid token (and therefore actor) is present. However, when I make a JSON API request without a token, I receive a generic 400 error like:

{
  "errors": [
    {
      "code": "something_went_wrong",
      "status": "400",
      "title": "SomethingWentWrong",
      "detail": "..."
    }
  ]
}


I want it to return a 403 Forbidden instead. So I tried this policy:

policy action(:me) do
  access_type :strict
  forbid_unless actor_present()
  authorize_if always()
end


Now, when there’s no token, it correctly returns 403 Forbidden.

But unfortunately, when there is a token, I get a 404 Not Found instead:

{
  "errors": [
    {
      "code": "not_found",
      "status": "404",
      "title": "Entity Not Found",
      "detail": "No user record found with ``"
    }
  ]
}


Even when I adjusted the code further, I still get 404.
How can I ensure:

* 403 Forbidden is returned when no token is provided
* 200 OK (with user info) is returned when a valid token exists
instead of getting a 404?

By the way, my user is using multitenancy global? true
I think i miss a part 😢🤔
Thank you in advance
Solution
Oh i changed my order of policies it shows :thinkies: 🥲

this was the last line of policies and i move
bypass always() do
      authorize_if {MishkaCms.Accounts.Checks.AccessPermissions,
                    permissions: ["admin:dashboard:*", "admin:api:*", "*"]}
    end

and i move top of
policy action(:me) do
      access_type :strict
      forbid_unless actor_present()
      authorize_if always()
    end

And for preventing warning of no actor
  read :me do
      description "Get the current authenticated user"
      get? true

      # filter expr(id == ^actor(:id))

      prepare fn query, context ->
        if context.actor do
          query
          |> Ash.Query.filter(id == ^context.actor.id)
          |> Ash.Query.load([:permissions, :permission_values, :site])
        else
          query |> Ash.Query.filter(expr(false))
        end
      end
    end


:thinkies:
Was this page helpful?