SafeRPC has two runtime authorization layers on the server side.
Capabilities
A capability is a token plus an operation scope:
cap = SafeRPC.Capability.new(token: "secret", ops: [{MyApp.AdminRPC, :status}])
{:ok, _pid} =
MyApp.AdminRPCServer.start_link(
socket: "/run/my-app/rpc.sock",
capability: cap
)The client sends the token per request:
SafeRPC.call(socket, {MyApp.AdminRPC, :status}, %{}, cap: "secret")Use ops: :all to allow every operation for that token.
Built-in operations such as :safe_rpc_atoms and :safe_rpc_describe are checked the same way. Include them explicitly if a restricted capability should allow discovery or atom preparation.
Authorizers
An authorizer can inspect the full decoded request:
defmodule MyApp.RPCAuthorizer do
@behaviour SafeRPC.Authorizer
def authorize(%{op: {MyApp.AdminRPC, :status}}, _context), do: :ok
def authorize(_request, _context), do: {:error, :forbidden}
endConfigure it on the server:
MyApp.AdminRPCServer.start_link(
socket: "/run/my-app/rpc.sock",
authorizer: MyApp.RPCAuthorizer,
auth_context: %{service: :my_app}
)SafeRPC intentionally does not define users, tenants, roles, sessions, or resource semantics. Those belong in the application authorizer.