AshGrant.Introspect (AshGrant v0.14.1)

Copy Markdown View Source

Permission introspection helpers for various use cases.

This module provides functions to query and inspect permissions at runtime, useful for:

  • Admin UI: Display what permissions a user has
  • Permission Management: List all available permissions for a resource
  • Debugging: Check why access is allowed or denied
  • API Responses: Return allowed actions to clients

Functions Overview

FunctionUse CaseReturns
actor_permissions/3Admin UIAll permissions with status
available_permissions/1Permission managementAll possible permissions
can?/4Debugging:allow or :deny with details
allowed_actions/3API responseList of allowed actions
permissions_for/3Raw accessPermission strings from resolver

Examples

# Admin UI: What can this user do?
Introspect.actor_permissions(Post, current_user)
# => [%{action: "read", allowed: true, scope: "always", field_groups: []}, ...]

# Permission management: What permissions exist?
Introspect.available_permissions(Post)
# => [%{permission_string: "post:*:read:always", action: "read", scope: "always", field_group: nil}, ...]

# Debugging: Can user do this?
Introspect.can?(Post, :update, user)
# => {:allow, %{scope: "own", instance_ids: nil, field_groups: []}}

# API: What actions are available?
Introspect.allowed_actions(Post, user)
# => [:read, :create, :update]

Summary

Functions

Returns all permissions for a resource with their status for a given actor.

Returns list of allowed actions for an actor.

Returns all available permissions for a resource.

Simple permission check returning :allow or :deny with details.

Returns raw permissions from the resolver for an actor.

Types

available_permission()

@type available_permission() :: %{
  permission_string: String.t(),
  action: String.t(),
  scope: String.t(),
  scope_description: String.t() | nil,
  field_group: String.t() | nil
}

permission_status()

@type permission_status() :: %{
  action: String.t(),
  allowed: boolean(),
  denied: boolean(),
  scope: String.t() | nil,
  instance_ids: [String.t()] | nil,
  field_groups: [String.t()]
}

Functions

actor_permissions(resource, actor, opts \\ [])

@spec actor_permissions(module(), term(), keyword()) :: [permission_status()]

Returns all permissions for a resource with their status for a given actor.

Useful for Admin UI to display what a user can or cannot do.

Options

  • :context - Additional context to pass to the resolver

Examples

iex> Introspect.actor_permissions(Post, %{role: :editor})
[
  %{action: "read", allowed: true, scope: "always", denied: false, instance_ids: nil, field_groups: []},
  %{action: "update", allowed: true, scope: "own", denied: false, instance_ids: nil, field_groups: []},
  %{action: "destroy", allowed: false, scope: nil, denied: false, instance_ids: nil, field_groups: []}
]

allowed_actions(resource, actor, opts \\ [])

@spec allowed_actions(module(), term(), keyword()) :: [atom()] | [map()]

Returns list of allowed actions for an actor.

Useful for API responses to tell clients what they can do.

Options

  • :context - Additional context to pass to the resolver
  • :detailed - When true, returns detailed info instead of just action names

Examples

iex> Introspect.allowed_actions(Post, %{role: :editor})
[:read, :create, :update]

iex> Introspect.allowed_actions(Post, %{role: :editor}, detailed: true)
[
  %{action: :read, scope: "always", instance_ids: nil, field_groups: []},
  %{action: :create, scope: "always", instance_ids: nil, field_groups: []},
  %{action: :update, scope: "own", instance_ids: nil, field_groups: []}
]

available_permissions(resource)

@spec available_permissions(module()) :: [available_permission()]

Returns all available permissions for a resource.

Useful for permission management UI to show what permissions can be assigned.

Examples

iex> Introspect.available_permissions(Post)
[
  %{permission_string: "post:*:read:always", action: "read", scope: "always", scope_description: nil, field_group: nil},
  %{permission_string: "post:*:read:own", action: "read", scope: "own", scope_description: "...", field_group: nil},
  ...
]

can?(resource, action, actor, opts \\ [])

@spec can?(module(), atom(), term(), keyword()) :: {:allow, map()} | {:deny, map()}

Simple permission check returning :allow or :deny with details.

Useful for debugging authorization issues.

Options

  • :context - Additional context to pass to the resolver

Examples

iex> Introspect.can?(Post, :read, %{role: :editor})
{:allow, %{scope: "always", instance_ids: nil, field_groups: []}}

iex> Introspect.can?(Post, :destroy, %{role: :viewer})
{:deny, %{reason: :no_permission}}

iex> Introspect.can?(Post, :read, nil)
{:deny, %{reason: :no_actor}}

permissions_for(resource, actor, opts \\ [])

@spec permissions_for(module(), term(), keyword()) :: [String.t()]

Returns raw permissions from the resolver for an actor.

Useful when you need direct access to permission strings.

Options

  • :context - Additional context to pass to the resolver

Examples

iex> Introspect.permissions_for(Post, %{role: :editor})
["post:*:read:always", "post:*:update:own", "post:*:create:always"]