gesmuni / laravel-auth-base
Core domain interfaces and entities for Gesmuni Auth - a mode-agnostic RBAC authentication library
Package info
gitlab.gitlab.videoatencion.com/gesmuni/php-laravel/laravel-auth-base.git
pkg:composer/gesmuni/laravel-auth-base
Requires
- php: ^8.2
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
This package is not auto-updated.
Last update: 2026-05-08 11:06:44 UTC
README
Core domain interfaces and entities for Gesmuni Auth - a mode-agnostic RBAC authentication and authorization library.
This package provides the pure domain layer with interfaces, entities, value objects, and DTOs. It has zero dependencies and can be used in any PHP 8.1+ project. Concrete implementations (Eloquent adapters, HTTP clients, etc.) are provided in separate packages.
Features
- Mode-Agnostic Architecture: Same interface for Local, Client, and Service deployment modes
- Ports & Adapters Pattern: Clean separation between domain contracts and implementations
- RBAC with Namespaces: Per-application role and permission isolation
- Group-Based Permissions: Hierarchical groups with role inheritance
- Two Actor Types: HUMAN (with roles) and APPLICATION (authentication only)
- PHP 8.1+ Features: Native enums, readonly properties, typed properties
- Zero Dependencies: Pure PHP domain layer
Installation
composer require gesmuni/laravel-auth-base
Package Structure
src/
├── Entities/ # 13 domain entities
│ ├── Actor.php # HUMAN or APPLICATION actors
│ ├── Role.php # Roles with permissions
│ ├── Permission.php # Atomic permissions
│ ├── Group.php # Hierarchical groups
│ └── ...
├── ValueObjects/ # Enums and value objects
│ ├── ActorType.php # HUMAN | APPLICATION
│ ├── ActorStatus.php # ACTIVE | SUSPENDED | BLOCKED | INACTIVE | DELETED
│ ├── PermissionSlug.php # Validated namespace.resource:action
│ └── ...
├── Contracts/
│ ├── Services/ # Public API interfaces
│ │ ├── AuthQuery.php # Read-only operations
│ │ └── AuthAdmin.php # Read + write operations
│ └── Repositories/ # Repository ports (13 interfaces)
│ ├── ActorRepository.php
│ └── ...
├── DTOs/ # Data Transfer Objects
│ ├── Input/ # CreateActorInput, UpdateActorInput, etc.
│ └── Result/ # AuthResult
└── Exceptions/ # Domain exceptions
├── ActorNotFoundException.php
├── PermissionDeniedException.php
└── ...
Core Concepts
Entities
The domain model consists of 13 entities:
- Actor: HUMAN or APPLICATION with authentication and status
- Role: Container for permissions within an app namespace
- Permission: Atomic actions validated as
namespace.resource:action - RolePermission: N:M relationship between roles and permissions
- AppRegistration: Application namespaces (Service Mode)
- AppUser: Actor-to-app bindings with per-app status
- ActorRole: Direct role assignments to actors (Channel 1)
- AppData: Per-app key-value data storage
- AuditLog: Audit trail for all operations
- RefreshToken: SHA-256 hashed tokens with rotation
- Group: Hierarchical groups forming a tree
- GroupMember: Actor membership in groups
- GroupRole: Role assignments to groups (Channel 2)
Value Objects
- ActorType enum:
HUMAN,APPLICATION - ActorStatus enum:
ACTIVE,SUSPENDED,BLOCKED,INACTIVE,DELETED - AppStatus enum:
ACTIVE,SUSPENDED - AppUserStatus enum:
PENDING,ACTIVE,SUSPENDED,REMOVED - PermissionSlug: Immutable value object with validation (
namespace.resource:action)
Public Interfaces
AuthQuery (Read-Only)
interface AuthQuery
{
// Permission checks
public function hasPermission(string $actorId, string $permissionSlug): bool;
public function hasAnyPermission(string $actorId, array $permissionSlugs): bool;
public function hasAllPermissions(string $actorId, array $permissionSlugs): bool;
public function getAllPermissions(string $actorId): array;
// Actor queries
public function getActor(string $actorId): Actor;
public function getActorByEmail(string $email): ?Actor;
public function getActorDirectRoles(string $actorId): array;
public function getActorEffectiveRoles(string $actorId): array;
// App data
public function getAppData(string $actorId, string $key): ?string;
public function getAllAppData(string $actorId): array;
// Validation
public function validateCredentials(string $email, string $password): AuthResult;
public function isActorActive(string $actorId): bool;
// Groups
public function getActorGroups(string $actorId): array;
public function getGroupMembers(string $groupId): array;
public function getGroupRoles(string $groupId): array;
public function getGroupAncestors(string $groupId): array;
public function getGroupDescendants(string $groupId): array;
}
AuthAdmin (Read + Write)
AuthAdmin extends AuthQuery and adds write operations:
interface AuthAdmin extends AuthQuery
{
// Actors: create, update, delete, setStatus
// Roles: create, update, delete, list, assignPermissions, revokePermissions
// Permissions: register, registerMultiple, delete, list, listByGroup
// AppUser: link, unlink, setStatus, assignRole, revokeRole
// AppData: set, delete, clear
// AppRegistration: register, suspend, delete, deleteGlobal
// Groups: create, update, delete, setParent, addMember, removeMember, assignRole, revokeRole
}
Usage Examples
Example 1: Permission Check
use Gesmuni\Auth\Base\Contracts\Services\AuthQuery;
class PostController
{
public function __construct(private AuthQuery $auth) {}
public function edit(Post $post)
{
if (!$this->auth->hasPermission($userId, 'blog.post:edit')) {
throw new PermissionDeniedException();
}
// Edit post...
}
}
Example 2: Create Actor and Assign Role
use Gesmuni\Auth\Base\Contracts\Services\AuthAdmin;
use Gesmuni\Auth\Base\DTOs\Input\CreateActorInput;
use Gesmuni\Auth\Base\ValueObjects\ActorType;
class UserService
{
public function __construct(private AuthAdmin $auth) {}
public function createUser(string $email, string $name, string $password)
{
// Create actor
$actor = $this->auth->createActor(new CreateActorInput(
type: ActorType::HUMAN,
email: $email,
name: $name,
password: $password,
));
// Assign role
$this->auth->assignRoleToActor($actor->id, null, $editorRoleId);
return $actor;
}
}
Example 3: Group-Based Permissions
// Create a group
$engineeringGroup = $auth->createGroup(new CreateGroupInput(
name: 'Engineering',
parentId: $everyoneGroupId,
));
// Add member
$auth->addMemberToGroup($userId, $engineeringGroup->id);
// Assign role to group (all members inherit)
$auth->assignRoleToGroup($engineeringGroup->id, null, $developerRoleId);
// Check permission (includes group roles)
$hasPermission = $auth->hasPermission($userId, 'code.repo:push');
Operating Modes
The interfaces are designed to work identically across three deployment modes:
Local Mode
The application imports the library directly. No network calls, null app_id.
Implementation package: gesmuni/laravel-auth-local
// In Local Mode
$authQuery->hasPermission($userId, 'content:edit'); // Resolves to "app.content:edit" implicitly
Client Mode
The application uses an HTTP wrapper that calls a remote auth service. Consumer code doesn't change.
Implementation package: gesmuni/laravel-auth-client
// In Client Mode (same code!)
$authQuery->hasPermission($userId, 'content:edit'); // HTTP call to remote service
Service Mode
The library is mounted behind an HTTP/gRPC API server. Multi-tenant with per-app namespaces.
Implementation package: gesmuni/laravel-auth-service
Domain Rules
Namespaces
- Each application operates within its own namespace (e.g.,
crm,shop,blog) - The
_authnamespace is reserved for system management - Permission slugs follow format:
namespace.resource:action - In Local Mode, namespace is implicit (
app.)
Groups
- All groups form a single tree rooted at the system group
everyone everyonecannot have roles assigned (prevents unintended global grants)- Cycles are prevented:
setGroupParent()validates the tree structure - Role inheritance: actors inherit roles from their groups AND all ancestor groups
Two-Channel Role Assignment
Effective permissions are the union of:
- Direct channel:
ActorRole(direct actor-to-role assignments) - Group channel:
GroupRole(role assigned to actor's groups + ancestors)
System Protection
- System roles (
is_system = true) cannot be deleted - System groups (e.g.,
everyone) cannot be deleted or re-parented everyonecannot have roles assigned
Actor Lifecycle
ACTIVE ⇄ SUSPENDED (temporary, reversible)
ACTIVE → BLOCKED (permanent, irreversible except to DELETED)
ACTIVE → INACTIVE (auto-timeout, auto-reactivates on login)
Any → DELETED (soft delete, retained for audit)
Exception Handling
All domain exceptions extend AuthException and include a context array:
try {
$auth->deleteRole($roleId);
} catch (SystemRoleProtectedException $e) {
// $e->context == ['role_id' => '...', 'role_name' => '...']
Log::warning('Attempted to delete system role', $e->context);
}
Available exceptions:
ActorNotFoundExceptionPermissionDeniedExceptionInvalidNamespaceExceptionSystemRoleProtectedExceptionCyclicGroupReferenceExceptionSystemGroupProtectedException
Companion Packages
| Package | Description |
|---|---|
gesmuni/laravel-auth-base | This package - Core domain interfaces and entities |
gesmuni/laravel-auth-local | (Coming soon) Local Mode implementation with Eloquent, migrations, service provider |
gesmuni/laravel-auth-client | (Coming soon) Client Mode HTTP wrapper |
gesmuni/laravel-auth-service | (Coming soon) Service Mode API server |
Development
Running Tests
composer test
Static Analysis
composer phpstan
Design Documentation
For the complete architectural specification, see auth-design-v1.md.
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
License
This project is licensed under the GNU Affero General Public License v3.0 or later - see the LICENSE file for details.
Credits
Part of the Gesmuni authentication and authorization ecosystem.