neophp / permissions-package
Generic permission-checking middleware for NeoPHP, usable with any auth system
Requires
- php: >=8.5
README
A generic, named-permission system for NeoPHP — grant and check permissions for any user, from any authentication system. This package never assumes which auth system you use, how you manage sessions, or which user entity you have. You always tell it explicitly.
Structure
permissions-package/
├── composer.json
├── README.md
├── src/
│ ├── NeoPermissionsPackage.php
│ ├── Service/
│ │ └── PermissionManager.php
│ └── Middleware/
│ └── PermissionMiddleware.php
└── database/
├── Entity/
│ └── UserPermission.php
├── Repository/
│ └── UserPermissionRepository.php
└── Migrations/
└── MigrationVersion_Permissions_1.php
Design principle: zero assumptions, zero coupling
This package does not know about neo-admin-package, NeoPHP's core
AuthManager, or any other authentication system — and it never will.
Every method takes explicit (userType, userId) parameters instead of a
user object, and PermissionMiddleware requires an explicit session key
instead of guessing one. This makes it usable with:
neo-admin-package'sAdminAuthManager- NeoPHP's core
AuthManager - A fully custom authentication system
- Multiple different systems in the same project, simultaneously
No other package is ever modified to make this work.
Installation
php bin/neo package:require neophp/permissions-package --project=MyProject
Register it in the project's Config/app.config.php:
return [ // ... 'packages' => [ \Vendor\NeoPHP\PermissionsPackage\NeoPermissionsPackage::class, ], ];
Run the migration:
php bin/neo database:migration:migrate --project=MyProject
The (userType, userId) pair
Every method identifies a user by their entity's class-string plus their ID — not by a user object. This is what makes the package usable with any user entity, from any auth system:
$permissions->grant(\Vendor\NeoPHP\AdminPackage\Database\Entity\AdminUser::class, $user->getId(), 'users.delete');
Granting and checking permissions in your own code
use Vendor\NeoPHP\PermissionsPackage\Service\PermissionManager; // Grant $permissions->grant(AdminUser::class, $userId, 'users.delete'); // Check if ($permissions->hasPermission(AdminUser::class, $userId, 'users.delete')) { // ... } // Revoke $permissions->revoke(AdminUser::class, $userId, 'users.delete'); // List everything a user currently has $permissions->listPermissionsFor(AdminUser::class, $userId); // list<string>
Permission names are free-form strings — this package does not enforce
or validate a naming scheme. A resource.action convention
(users.delete, settings.edit, articles.publish) is recommended but
not required.
Protecting a route with PermissionMiddleware
PermissionMiddleware reads a user ID directly from the session, at a
key you provide explicitly — it never assumes where that key lives.
use Neo\Core\Security\Middleware\Attribute\Middleware; use Vendor\NeoPHP\PermissionsPackage\Middleware\PermissionMiddleware; #[Route(path: '/{id}/delete', name: 'delete', methods: ['POST'])] #[Middleware( use: PermissionMiddleware::class, onError: 'block', message: 'You do not have permission to delete users.', params: [ 'permission' => 'users.delete', 'userType' => AdminUser::class, 'sessionKey' => '_neo_admin_auth_user_id', ], )] public function delete(int $id): Response { // ... }
Finding the right sessionKey
If you're integrating with neo-admin-package (^1.1 or later), its
session key is configurable in that project's
Config/Packages/NeoAdmin/admin-system.config.php under
auth.session_key (defaults to _neo_admin_auth_user_id). Use whatever
value is configured there — this package has no knowledge of it and
cannot read that config for you.
If you're using NeoPHP's core AuthManager, or a fully custom system,
use whatever session key your own login code writes the user ID to.
If no user ID is found at that key, the middleware denies access — the same behavior as an unauthenticated request.
What this package does not do
- No permission catalog or admin UI to manage permissions visually —
granting/revoking is done entirely through
PermissionManager's API, in your own code (a CLI command or admin page, if you want one, is your project's responsibility to build) - No role system, no hierarchy — this is flat, named permissions per user. If you need something more structured, build a "role" concept in your own project by grouping permission grants together
- No validation of permission name format — any string is accepted
License
MIT