CakePHP TinyAuth Demo

April 11, 2026 · View on GitHub

A demo application showcasing TinyAuth and TinyAuth Backend plugins for CakePHP 5.x.

Features

  • Role-based access control (RBAC) with database-backed permissions
  • TinyAuth Backend admin interface at /admin/auth/
  • Role simulation for testing different permission levels
  • Demo controllers showing protected and public actions
  • Resource-level permissions with scoped access (entity-level authorization)

Requirements

  • PHP 8.2+
  • MySQL/MariaDB
  • DDEV (recommended) or any local development environment

Quick Start with DDEV

# Clone the repository
git clone https://github.com/dereuromark/cakephp-tinyauth-demo.git
cd cakephp-tinyauth-demo

# Start DDEV
ddev start

# Install dependencies
ddev composer install

# Set up configuration if the files do not exist yet
test -f config/.env || cp config/.env.example config/.env
test -f config/app_local.php || cp config/app_local.example.php config/app_local.php

# Review config/.env and make sure APP_FULL_BASE_URL and SECURITY_SALT are correct.
# DDEV will usually create config/.env and composer install will usually create
# config/app_local.php for you on first setup.

# Run migrations
ddev exec bin/cake migrations migrate
ddev exec bin/cake migrations migrate -p TinyAuthBackend

# Sync controllers, actions, and resource entities into the TinyAuth
# backend tables. Equivalent to clicking Sync in /admin/auth/sync.
ddev exec bin/cake tiny_auth_backend sync

# Seed demo data (roles, scopes, users, resources, articles, projects)
ddev exec bin/cake seed_demo_data

# Visit the app
ddev launch

Demo Roles

The demo includes three roles with hierarchical permissions:

RoleIDDescription
admin3Full access to everything
moderator2Access to reports and moderation features
user1Basic user access

Demo Users

The seeder creates sample users for testing resource permissions:

UserRoleTeamPurpose
aliceUserEngineeringTest "own" scope - owns some articles/projects
bobUserEngineeringSame team as Alice - test "team" scope
charlieUserMarketingDifferent team - test cross-team restrictions
dianaModeratorSalesHigher role with broader permissions
adminAdminNoneFull access to everything

URLs

  • Home: / - Shows current role and available actions
  • TinyAuth Admin: /admin/auth/ - Permission management interface
  • Role Switcher: Use the dropdown on the home page to simulate different roles
  • Articles Demo: /articles - Resource permissions with "own" scope
  • Projects Demo: /projects - Resource permissions with "team" scope

Resource-Level Permissions Demo

TinyAuth Backend supports entity-level permissions beyond controller/action ACL. This demo showcases two examples:

Articles (Own Scope)

Demonstrates permissions where users can only edit/delete their own content:

RoleViewEditDelete
UserAllOwn onlyOwn only
ModeratorAllAllOwn only
AdminAllAllAll

How it works: The "own" scope compares article.user_id with user.id.

Projects (Team Scope)

Demonstrates team-based access where users can access content from their team:

RoleViewEditDelete
UserTeam onlyOwn onlyNone
ModeratorAllTeam onlyOwn only
AdminAllAllAll

How it works: The "team" scope compares project.team_id with user.team_id.

Demo Scopes

Scopes define conditions for entity-level access control. The seeder creates these scopes:

ScopeEntity FieldUser FieldUse Case
ownuser_ididUser can only access their own records
teamteam_idteam_idUser can access records from their team
departmentdepartment_iddepartment_idDepartment-based access
companycompany_idcompany_idCompany-wide access

How Scopes Work

When a role has a resource permission with a scope attached, the condition is evaluated:

entity.{entity_field} === user.{user_field}

Example: A "user" role with "edit" ability on "Articles" with "own" scope means:

  • User can edit articles where article.user_id === user.id

Without a scope, the permission grants access to all entities.

Testing Resource Permissions

  1. Visit the home page and select a role (e.g., "User")
  2. Select a user identity (e.g., "alice" - User ID 1, Team ID 1)
  3. Navigate to /articles:
    • You'll see all articles (view: no scope restriction)
    • Only articles you own will show edit/delete options
  4. Navigate to /projects:
    • You'll only see projects from your team
    • Only your own projects can be edited

Try switching between users to see how permissions change:

  • alice (Engineering): Can see Engineering projects, edit own
  • bob (Engineering): Same team as Alice, can see same projects
  • charlie (Marketing): Different team, sees only Marketing projects
  • diana (Moderator): Can see all projects, edit within her team

Configuration

Roles Configuration

Roles are defined in config/roles.php:

return [
    'user' => 1,
    'moderator' => 2,
    'admin' => 3,
];

TinyAuth Backend

The admin interface provides:

  • Dashboard: Overview of controllers, actions, and roles
  • ACL: Manage role-based permissions per action
  • Allow: Configure public (unauthenticated) actions
  • Roles: Manage role definitions
  • Resources: Entity-level permissions (with scope support)
  • Scopes: Define reusable conditions for entity access

Screenshots

Dashboard

Overview of your authorization setup at a glance.

Dashboard

ACL Permissions

Manage which roles can access each controller action.

ACL

Public Actions (Allow)

Configure which actions are publicly accessible without authentication.

Allow

Roles

Define and organize your role hierarchy.

Roles

Resources

Entity-level permissions with scoped access (e.g., users can only edit their own articles).

Resources

Scopes

Reusable conditions for fine-grained entity access control.

Scopes

Implementation Guide

Wiring cakephp/authorization

For the FullBackend, NativeAuth, and ExternalRoles strategies, the demo wires the Authorization plugin with TinyAuthBackend\Policy\TinyAuthResolver. One allowlist, one policy, both entity checks and query scoping go through the same DB rules:

// src/Application.php
use Authorization\AuthorizationService;
use TinyAuthBackend\Policy\TinyAuthResolver;

public function getAuthorizationService(ServerRequestInterface $request): AuthorizationServiceInterface
{
    $resolver = new TinyAuthResolver([
        \App\Model\Entity\Article::class,
        \App\Model\Entity\Project::class,
        \App\Model\Table\ArticlesTable::class,
        \App\Model\Table\ProjectsTable::class,
    ]);

    return new AuthorizationService($resolver);
}

Controllers then use the idiomatic calls:

$article = $this->Articles->get($id);
$this->Authorization->authorize($article, 'edit');

$query = $this->Authorization->applyScope($this->Articles->find());

Both dispatch through TinyAuthPolicyTinyAuthService → DB rules → role hierarchy → scopes.

For apps that don't load cakephp/authentication, the plugin also ships TinyAuthBackend\Identity\EntityIdentity, a minimal wrapper that turns any Cake entity into a valid Authorization\IdentityInterface — drop it on the request under the configured identity attribute from your own middleware and you're done.

Using TinyAuthService in Controllers

use TinyAuthBackend\Service\TinyAuthService;

// Check if user can access specific entity
$service = new TinyAuthService();
$canEdit = $service->canAccess(
    $userRoleAlias,    // e.g., 'User'
    'Article',         // Resource name
    'edit',            // Ability
    $article,          // Entity being accessed
    $user              // Current user
);

// Get scope conditions for query filtering
$conditions = $service->getScopeCondition(
    $userRoleAlias,
    'Article',
    'view',
    $user
);
// Returns: null (no access), [] (full access), or ['user_id' => 1] (scoped)

Permission Checking Flow

  1. Controller/Action level: TinyAuth ACL checks if role can access the action
  2. Entity level: Your controller uses TinyAuthService to check resource permissions
  3. Query filtering: Use scope conditions to filter database queries

License

MIT License