Packages

WebSocket-first Elixir framework with auto-generated HTTP MCP APIs

Current section

Files

Jump to
dialup lib auth grants.ex
Raw

lib/auth/grants.ex

defmodule Dialup.Auth.Grants do
@moduledoc """
Helpers for scoping MCP grants based on authentication state.
Unauthenticated sessions receive minimal read-only capabilities. After login,
pages should extend this base grant with role-specific capabilities in
`agent_grant/1`.
"""
@minimal_capabilities [:read_scene, :issue_browser_url]
@minimal_projections [:state, :actions]
@doc "Base grant for unauthenticated sessions (agent-first / pre-login)."
@spec guest_grant() :: map()
def guest_grant do
%{
capabilities: @minimal_capabilities,
projections: @minimal_projections,
expires_in: :timer.minutes(15),
require_version: true
}
end
@doc """
Returns guest grant when `current_user` is absent, otherwise `logged_in_grant/1`.
Pages can pass extra capabilities to merge when authenticated:
def agent_grant(assigns) do
Dialup.Auth.Grants.for_user(assigns, capabilities: [:add_item])
end
"""
@spec for_user(map(), keyword()) :: map()
def for_user(assigns, opts \\ [])
def for_user(%{current_user: user}, opts) when not is_nil(user) do
logged_in_grant(user, opts)
end
def for_user(%{dialup_auth_enabled?: true}, _opts), do: guest_grant()
def for_user(_assigns, _opts), do: logged_in_grant(nil, [])
@doc "Default authenticated grant; override capabilities via opts."
@spec logged_in_grant(map() | struct(), keyword()) :: map()
def logged_in_grant(_user, opts) do
capabilities = Keyword.get(opts, :capabilities, :all)
projections = Keyword.get(opts, :projections, [:state, :regions, :actions])
%{
capabilities: capabilities,
projections: projections,
expires_in: Keyword.get(opts, :expires_in, :timer.minutes(15)),
require_version: Keyword.get(opts, :require_version, true)
}
end
end