nuxia/acl-bundle
nuxia/acl-bundle is a lightweight ACL package for Laravel/PHP applications, providing role- and permission-based access control so you can protect routes, resources, and actions with configurable rules. It helps centralize authorization logic and keep application code clean.
First, a reality check: despite the name pairing you'll often see in Laravel shops, nuxia/acl-bundle is a Symfony bundle, not a Laravel package. It wraps Symfony's symfony/security-acl component to provide annotation-driven permission checks. If you're committing to a Laravel codebase, this package will not drop in — there is no Laravel service provider, facade, or config file.
Assuming a Symfony (2.x/3.x era) project:
composer require nuxia/acl-bundle symfony/security-acl
app/AppKernel.php (Symfony 2/3) or config/bundles.php (Symfony 3.3+):
new Nuxia\AclBundle\NuxiaAclBundle(),
acl_classes, acl_entries, acl_object_identities, acl_object_identity_ancestors, acl_security_identities). Run the schema tool or the ACL init console command before anything works.nuxia_acl: in config.yml — this is where you point at your user entity and declare which permission names map to which masks.Where to look first: the bundle's annotation class (Nuxia\AclBundle\Annotations\Acl) and its manager service definition. There is essentially no README worth reading (2 stars, 0 dependents, 0 examples), so the annotations and service container config are the documentation.
First use case — annotate a controller action:
use Nuxia\AclBundle\Annotations\Acl;
/**
* @Acl(permissions={"VIEW"}, object="post")
*/
public function showAction(Post $post) { /* ... */ }
This is the lowest-friction entry point and mirrors Symfony's native @Security annotation, but resolves permissions against the ACL provider instead of the voter system.
Annotation guard on controller actions. The bundle's core value is letting you express required permissions declaratively on methods, resolving the target object from a route parameter or argument name. Use this for CRUD controllers where the permission is obvious and static per action.
Programmatic grant/revoke via the manager service. For admin tooling ("share this post with user X", "make Y an editor"), inject the ACL manager and call grant/revoke directly. This is the pattern that actually replaces hand-rolled permission tables:
$aclManager->grant($post, $user, ['EDIT']);
$aclManager->revoke($post, $role, ['VIEW']);
Object-level vs class-level. ACL supports two scopes: a class-wide identity (the equivalent of "all posts can be viewed") and a per-object identity (this specific post). Use class-level for coarse defaults and object-level only for per-item overrides — mixing the two without discipline is the #1 source of "why can this user see this?" tickets.
Mask building for fine-grained control. The underlying MaskBuilder composes atomic permissions (VIEW, EDIT, CREATE, DELETE, OWNER) into a bitmask. If your app needs "edit but not delete," build custom masks rather than granting EDIT and special-casing DELETE in a voter elsewhere.
Security identity is a user or a role. Grants are stored against a SecurityIdentity, which can be a UserSecurityIdentity (class + identifier) or a RoleSecurityIdentity. Effective permissions are the union of both. Design your permission model around "what does this role grant globally" plus "what does this user get on this object," and don't be surprised when a role grant shows up on an object check.
Integration tip: wrap annotation-driven checks so that a PermissionDeniedException produces a clean 403 rather than a 500 — the annotation listener throws, and without a kernel.exception handler you'll leak stack traces.
framework.annotations (or the equivalent reader) is enabled and that the bundle's listener is registered — with doctrine/annotations absent, the guard silently no-ops on some Symfony versions.AclProviderInterface directly.How can I help you explore Laravel packages today?