I'm trying to rewrite some of our custom websocket code to subscription. I had success in putting in the context. But I am running in an issue, when I would like to do authorization on who is able to subscribe to what. So not anyone can subscribe to every content_item_id.
I tried adding a resolve block (but that doesn't seem to work). Is there another way to do authorization?
subscription do
field :on_message_added, :message do
arg :content_item_id, non_null(:id)
topic fn args ->
args.content_item_id
end
trigger :send_message, topic: fn message ->
message.content_item_id
end
end
end
So I did some more research, but I managed to get resolve working. It is actually triggered.
def subscribe_to_messages_on_content_item(%{content_item_id: id}, %{context: %{actor: actor}, source: %{on_message_added: message}}) do
content_item = Repo.get(Schema.Content.Item, id) |> Repo.preload(Schema.Content.Item.authorization_preloads())
with {:ok, _content_item} <- Schema.Content.Item.authorize(content_item, actor, :read) do
{:ok, message}
end
end
It seems that this not triggered for each subscription, but for each message that's being send to each user. For performance reasons I'd rather have my authentication in the set up of the subscription.
Perhaps it can be done in the topic function? The only problem is:
Hey @jfrolich this is a good insight. As you're noting, top level authorization with subscriptions doesn't make a lot of sense in the resolver because that isn't actually run when the subscription is created.
I'm in the middle of reworking the topic callback right now to support more complicated return values, which will include an {:error, reason} tuple.
Would the new topic callback also get the second argument that contains the context? That would completely solve my use case, as then it is possible to do authentication if a subscriber is able to join that topic.
yup!
Is it possible to completely skip sending a response on trigger as opposed to sending back an error? In our use case, we want to send data over subscriptions for only the posts the user is a member of, and not send anything at all in other cases.
Most helpful comment
yup!