kamaroly

kamaroly

How can I set the actor globally after the user successfully logs in, so that I don’t have to pass actor in every query.

Here 's what I did so far. It works if I manually set actor while querying, but it does not work with the actor set in the plugs.

I added set_actor in the Phoenix router plugs like the following

defmodule KamaroWeb.Router do
  use KamaroWeb, :router
  use AshAuthentication.Phoenix.Router
  import AshAuthentication.Plug.Helpers # <-- ADDED THIS

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, {KamaroWeb.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug :load_from_session
    plug :set_actor, :user # <-- ADDED THIS LINE
  end

I inspected and indeed confirmed that the actor is being set in the connection privates.

However when I inspect the actor from the Policy, it is nil.

defmodule Kamaro.Checks.Can do
  use Ash.Policy.SimpleCheck

  def describe(_opts) do
    "Check if a user/ actor has permission on a specific resource"
  end

  def match?(actor, context, opts) do
    dbg(actor) # <-- ACTOR IS NIL HERE
    {:ok, true}
  end
end

But, when I query by passing the actor like the following, the actor is not nil.

Stock.get_categories!(actor: user)

Here is how the resource policy is configured

  policies do
    policy action_type(:read) do
      authorize_if Kamaro.Checks.Can
    end
 end

Showing Posts 1 to 5

zachdaniel

zachdaniel

Creator of Ash

It is (intentionally) not possible to do this. You have to pass the actor to each call.

kamaroly

kamaroly OP

Thank you for the clarification @zachdaniel.

spacebat

spacebat

What is the intent behind that design decision? I can see points on both sides.

Benefits of explicit passing:

  • Leaving this to magic action-at-a-distance is bad
  • Making this assumption at the framework level could be a step too far
  • It complies with functional programming design, with more pure functions

Benefits of a global actor:

  • Leaving this to application code that might be insufficiently tested is bad
  • Its easier to ignore or remove a provided actor than to arrange for one to be present whenever needed
  • Only a few functions would be made impure by the introduction of this global context, most functions of interest already receive a context argument
zachdaniel

zachdaniel

Creator of Ash

We had this feature in 2.0, and ultimately removed it due to the multitude of footguns that presented themselves. Two such examples:

Code is no longer portable across processes

def mount(...) do
  Ash.set_actor(current_user)

  socket
  |> assign(:posts, Ash.read!(Post))
  # |> async_assign(:posts, fn -> Ash.read!(Post) end) # can't refactor to this
end

Given that many things that exist in the elixir ecosystem take a callback which will (or may or may not at the discretion of whats being called) run in another process, design that depends on the process context for security can be very problematic. Even something simple like using some Task.async to parallelize a few read actions risks introducing very non-obvious security bugs.

Actions calling other actions

Given this example:

# in a resource called Post
update :add_comment do
  change after_action(fn changeset, result, context -> 
    Comment
    |> Ash.Changeset.for_create(:create, %{}) # context is *not* passed through here
    |> Ash.create!()
  end)
end

If you do this:

Domain.add_comment!(post, actor: actor)

the call to Comment’s :create action does not receive an actor.

But if you do

Ash.set_actor(actor)

Domain.add_comment(post)

now the call to create a comment sees the process context actor and uses it. This is especially problematic because when you are writing logic in hooks, you are encapsulating logic, and the ability for some external source to make changes to how changes/hooks in your action run is very dangerous.

When we talked about removing it, we brought the above two things up, and got conflicting feedback that was especially illustrative of why this had to be removed.

Some people were upset to discover that Ash.set_actor set the actor in hooks as well, and realized there were likely bugs in their code.

But also, some people were relying on that behaviour, and saw it as a feature.

Leading up to Ash 3.0, the major design epic was missing major pieces in Ash core, specifically bulk actions and atomics. But the theme of changes made post 3.0 is less surprises/sharp edges and better developer experience, and the removal of the process dictionary features is more in line with those goals.

It may be more annoying, but without the process-dictionary features, your code does exactly what it looks like it does.

spacebat

spacebat

Well put, thanks.

— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
ChrisAmelia
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication): toke...
New
dillonoconnor
Is there any way to avoid the Hologram compiler running when using iex? It seems like the front-end code could potentially be disregarded...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
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
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews