Rephi.Authorization (Rephi v0.0.2)

View Source

The Authorization context manages roles, permissions, and user authorization.

This module implements a complete Role-Based Access Control (RBAC) system with hierarchical roles and permissions. It provides functions for:

  • Role management (CRUD operations)
  • Permission management (CRUD operations)
  • User-role assignments
  • User-permission assignments (direct)
  • Role-permission assignments
  • Role hierarchy management
  • Authorization checks

Examples

# Check if user has permission
iex> Authorization.can?(user, "users:edit")
true

# Check if user has role
iex> Authorization.has_role?(user, "admin")
false

# Get all user permissions (direct + inherited via roles)
iex> Authorization.get_user_permissions(user)
[%Permission{slug: "users:view"}, %Permission{slug: "users:create"}]

Role Hierarchy

Roles can inherit permissions from parent roles. For example:

  • admin role inherits from manager role
  • manager role inherits from user role
  • Users with admin role automatically have all manager and user permissions

Permission Categories

Permissions are organized by domain using colon notation:

  • users:* - User management permissions
  • roles:* - Role management permissions
  • permissions:* - Permission management permissions
  • system:* - System administration permissions

Summary

Functions

Assigns a parent role to a child role.

Assigns a permission directly to a user.

Checks if a user has a specific permission.

Flexible authorization check with keyword options.

Creates a new permission.

Creates a new role.

Deletes a permission from the system.

Deletes a role from the system.

Gets a single permission by ID, returning nil if not found.

Gets a single permission by ID, raising an exception if not found.

Gets a permission by its unique slug identifier.

Gets a single role by ID, returning nil if not found.

Gets a single role by ID, raising an exception if not found.

Gets a role by its unique slug identifier.

Gets all permissions for a role (including inherited permissions).

Gets all effective permissions for a user.

Gets all roles directly assigned to a user.

Checks if a user has a specific role assigned.

Returns the list of all permissions in the system.

Returns the list of all roles in the system.

Removes a parent role from a child role.

Removes a permission from a role.

Removes a permission from a user.

Removes a role assignment from a user.

Checks if a role has a specific permission.

Updates an existing permission.

Updates an existing role.

Functions

assign_parent_role(child_role, parent_role)

Assigns a parent role to a child role.

assign_permission_to_role(role, permission, opts \\ %{})

Assigns a permission to a role.

assign_permission_to_user(user, permission, opts \\ %{})

Assigns a permission directly to a user.

assign_role_to_user(user, role, opts \\ %{})

Assigns a role to a user.

Creates a relationship between a user and a role, optionally with metadata about who assigned it and why.

Parameters

  • user - The user struct
  • role - The role struct to assign
  • opts - Optional metadata (assigned_by, notes)

Examples

iex> Authorization.assign_role_to_user(user, admin_role)
{:ok, %UserRole{}}

iex> Authorization.assign_role_to_user(user, role, %{
...>   assigned_by: current_user.id,
...>   notes: "Promoted to admin"
...> })
{:ok, %UserRole{notes: "Promoted to admin"}}

iex> Authorization.assign_role_to_user(user, role)  # Already assigned
{:error, %Ecto.Changeset{}}

can?(user, permission_slug)

Checks if a user has a specific permission.

This function checks both direct permissions assigned to the user and permissions inherited through roles. It supports hierarchical role inheritance.

Parameters

  • user - The user struct to check permissions for
  • permission - Either a permission slug (string) or Permission struct

Examples

iex> Authorization.can?(user, "users:edit")
true

iex> Authorization.can?(user, permission_struct)
false

iex> Authorization.can?(nil, "users:edit")
false

iex> Authorization.can?(user, nil)
false

Permission Resolution Order

  1. Check direct user permissions
  2. Check permissions through assigned roles
  3. Check permissions through role hierarchy (parent roles)

can_by?(opts)

Flexible authorization check with keyword options.

This function provides a flexible interface for authorization checks using keyword arguments instead of positional parameters.

Parameters

  • opts - Keyword list with authorization options

Supported Options

  • user: user, permission: "permission:slug" - Check user permission
  • user: user, role: "role_slug" - Check user role

Examples

iex> Authorization.can_by?(user: user, permission: "users:edit")
true

iex> Authorization.can_by?(user: user, role: "admin")
false

iex> Authorization.can_by?(invalid: "option")
false

create_permission(attrs \\ %{})

Creates a new permission.

Parameters

  • attrs - A map of permission attributes

Examples

iex> Authorization.create_permission(%{
...>   name: "Export Users",
...>   slug: "users:export",
...>   description: "Export user data"
...> })
{:ok, %Permission{name: "Export Users", slug: "users:export"}}

iex> Authorization.create_permission(%{name: "", slug: ""})
{:error, %Ecto.Changeset{}}

create_role(attrs \\ %{})

Creates a new role.

Parameters

  • attrs - A map of role attributes

Examples

iex> Authorization.create_role(%{name: "Manager", slug: "manager"})
{:ok, %Role{name: "Manager", slug: "manager"}}

iex> Authorization.create_role(%{name: "", slug: ""})
{:error, %Ecto.Changeset{}}

delete_permission(permission)

Deletes a permission from the system.

Also removes all associated role-permission and user-permission assignments.

Parameters

  • permission - The permission struct to delete

Examples

iex> Authorization.delete_permission(permission)
{:ok, %Permission{}}

iex> Authorization.delete_permission(invalid_permission)
{:error, %Ecto.Changeset{}}

delete_role(role)

Deletes a role from the system.

Also removes all associated user-role and role-permission assignments.

Parameters

  • role - The role struct to delete

Examples

iex> Authorization.delete_role(role)
{:ok, %Role{}}

iex> Authorization.delete_role(invalid_role)
{:error, %Ecto.Changeset{}}

get_permission(id)

Gets a single permission by ID, returning nil if not found.

Parameters

  • id - The permission ID

Examples

iex> Authorization.get_permission(1)
%Permission{id: 1, name: "View Users"}

iex> Authorization.get_permission(999)
nil

get_permission!(id)

Gets a single permission by ID, raising an exception if not found.

Parameters

  • id - The permission ID

Examples

iex> Authorization.get_permission!(1)
%Permission{id: 1, name: "View Users", slug: "users:view"}

iex> Authorization.get_permission!(999)
** (Ecto.NoResultsError)

get_permission_by_slug(slug)

Gets a permission by its unique slug identifier.

Parameters

  • slug - The permission slug (e.g., "users:view", "roles:create")

Examples

iex> Authorization.get_permission_by_slug("users:view")
%Permission{slug: "users:view", name: "View Users"}

iex> Authorization.get_permission_by_slug("nonexistent")
nil

get_role(id)

Gets a single role by ID, returning nil if not found.

Parameters

  • id - The role ID

Examples

iex> Authorization.get_role(1)
%Role{id: 1, name: "Admin"}

iex> Authorization.get_role(999)
nil

get_role!(id)

Gets a single role by ID, raising an exception if not found.

Parameters

  • id - The role ID

Examples

iex> Authorization.get_role!(1)
%Role{id: 1, name: "Admin"}

iex> Authorization.get_role!(999)
** (Ecto.NoResultsError)

get_role_by_slug(slug)

Gets a role by its unique slug identifier.

Parameters

  • slug - The role slug (e.g., "admin", "user")

Examples

iex> Authorization.get_role_by_slug("admin")
%Role{slug: "admin", name: "Administrator"}

iex> Authorization.get_role_by_slug("nonexistent")
nil

get_role_permissions(role)

Gets all permissions for a role (including inherited permissions).

get_user_permissions(user)

Gets all effective permissions for a user.

Returns a deduplicated list of all permissions the user has access to, including both direct permissions and permissions inherited through roles and role hierarchy.

Parameters

  • user - The user struct

Examples

iex> Authorization.get_user_permissions(user)
[
  %Permission{slug: "users:view", name: "View Users"},
  %Permission{slug: "users:create", name: "Create Users"},
  %Permission{slug: "roles:view", name: "View Roles"}
]

Permission Sources

  1. Direct permissions: Permissions assigned directly to the user
  2. Role permissions: Permissions assigned to user's roles
  3. Inherited permissions: Permissions from parent roles in hierarchy

get_user_roles(user)

Gets all roles directly assigned to a user.

This does not include roles inherited through hierarchy.

Parameters

  • user - The user struct

Examples

iex> Authorization.get_user_roles(user)
[%Role{name: "Manager", slug: "manager"}]

has_role?(user, role_slug)

Checks if a user has a specific role assigned.

This function only checks for direct role assignments, not role inheritance.

Parameters

  • user - The user struct to check
  • role - Either a role slug (string) or Role struct

Examples

iex> Authorization.has_role?(user, "admin")
true

iex> Authorization.has_role?(user, admin_role)
false

iex> Authorization.has_role?(nil, "admin")
false

iex> Authorization.has_role?(user, nil)
false

list_permissions()

Returns the list of all permissions in the system.

Examples

iex> Authorization.list_permissions()
[
  %Permission{name: "View Users", slug: "users:view"},
  %Permission{name: "Create Users", slug: "users:create"}
]

list_roles()

Returns the list of all roles in the system.

Examples

iex> Authorization.list_roles()
[%Role{name: "Admin", slug: "admin"}, %Role{name: "User", slug: "user"}]

remove_parent_role(child_role, parent_role)

Removes a parent role from a child role.

remove_permission_from_role(role, permission)

Removes a permission from a role.

remove_permission_from_user(user, permission)

Removes a permission from a user.

remove_role_from_user(user, role)

Removes a role assignment from a user.

Parameters

  • user - The user struct
  • role - The role struct to remove

Examples

iex> Authorization.remove_role_from_user(user, admin_role)
{:ok, %UserRole{}}

iex> Authorization.remove_role_from_user(user, unassigned_role)
{:error, :not_found}

role_has_permission?(role, permission)

Checks if a role has a specific permission.

This function checks both direct permissions assigned to the role and permissions inherited through role hierarchy.

Parameters

  • role - The role struct to check
  • permission - Either a permission slug (string) or Permission struct

Examples

iex> Authorization.role_has_permission?(admin_role, "users:delete")
true

iex> Authorization.role_has_permission?(user_role, delete_permission)
false

iex> Authorization.role_has_permission?(role, "nonexistent:permission")
false

Permission Resolution

  1. Check permissions directly assigned to the role
  2. Check permissions inherited from parent roles (recursive)

update_permission(permission, attrs)

Updates an existing permission.

Parameters

  • permission - The permission struct to update
  • attrs - A map of attributes to update

Examples

iex> Authorization.update_permission(permission, %{
...>   description: "Updated description"
...> })
{:ok, %Permission{description: "Updated description"}}

iex> Authorization.update_permission(permission, %{slug: ""})
{:error, %Ecto.Changeset{}}

update_role(role, attrs)

Updates an existing role.

Parameters

  • role - The role struct to update
  • attrs - A map of attributes to update

Examples

iex> Authorization.update_role(role, %{name: "Senior Manager"})
{:ok, %Role{name: "Senior Manager"}}

iex> Authorization.update_role(role, %{slug: ""})
{:error, %Ecto.Changeset{}}