Fine-grained authorization for every API route and data resource. The plugin ships a combined RBAC + ABAC engine: roles define broad permission sets, while attribute policies let you express row-level or field-level rules like "users can only read their own records" without touching application code.
Requires an active ɳSelf+ license. Activate with nself license set nself_pro_... before installing.
nself plugin install access-controls
nself build
nself startAfter install, define a role and assign it to a user:
# Create a role
curl -X POST https://api.yoursite.com/roles \
-H "Authorization: Bearer $TOKEN" \
-d '{"name":"editor","description":"Can read and write content"}'
# Assign a permission to the role
curl -X POST https://api.yoursite.com/roles/{role_id}/permissions \
-H "Authorization: Bearer $TOKEN" \
-d '{"resource":"posts","action":"write"}'
# Assign the role to a user
curl -X POST https://api.yoursite.com/users/{user_id}/roles \
-H "Authorization: Bearer $TOKEN" \
-d '{"role_id":"{role_id}"}'
# Check authorization inline
curl -X POST https://api.yoursite.com/check \
-H "Authorization: Bearer $TOKEN" \
-d '{"user_id":"u1","resource":"posts","action":"write"}'| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | Yes | — | Postgres connection string (set by nSelf automatically) |
ACL_PLUGIN_PORT | No | 3027 | Port for the access-controls API server |
ACL_CACHE_TTL_SECONDS | No | 300 | How long to cache policy evaluations in memory |
ACL_MAX_ROLE_DEPTH | No | 10 | Maximum depth for hierarchical role inheritance |
ACL_DEFAULT_DENY | No | true | Deny all requests that do not match a policy (recommended) |
ACL_API_KEY | No | — | Optional static API key for service-to-service authorization checks |
ACL_RATE_LIMIT_MAX | No | 1000 | Max authorization check requests per window |
ACL_RATE_LIMIT_WINDOW_MS | No | 60000 | Rate limit window in milliseconds |
| Endpoint | Method | Description |
|---|---|---|
/check | POST | Evaluate whether a user has a given permission on a resource |
/roles | GET / POST | List or create roles |
/roles/:id | GET / PUT / DELETE | Read, update, or delete a role |
/roles/:id/permissions | GET / POST / DELETE | Manage permissions assigned to a role |
/permissions | GET / POST | List or create permission definitions |
/policies | GET / POST | List or create ABAC attribute policies |
/policies/:id | GET / PUT / DELETE | Read, update, or delete a policy |
/users/:user_id/roles | GET / POST / DELETE | Assign or revoke roles for a user |
/health | GET | Plugin health check |
| Table | Purpose |
|---|---|
np_acl_roles | Role definitions with names and descriptions |
np_acl_permissions | Permission definitions (resource + action pairs) |
np_acl_role_permissions | Many-to-many: roles to permissions |
np_acl_user_roles | Many-to-many: users to roles |
np_acl_policies | ABAC attribute policies (JSON condition expressions) |
np_acl_webhook_events | Outbound webhook delivery queue for policy change events |
Use roles for broad, static permissions (admin, editor, viewer). Use attribute policies when the decision depends on record-level data — for example, "a user can only delete posts they created" requires an ABAC policy that comparespost.created_by to the requesting user ID. Both systems are evaluated together; a request is allowed when either a role permission or an ABAC policy grants it (and no explicit deny overrides).
Hasura permissions are great for GraphQL-layer filtering. access-controls extends that to REST APIs, backend services, and programmatic checks inside your application logic. Use both together: Hasura for query-level filtering, access-controls for imperative checks in business logic and service-to-service calls.
All requests return 403 even for admins. Check that ACL_DEFAULT_DENY=true and that you have a role with the matching resource + action assigned to the user. Run nself plugin logs access-controls to see evaluation traces.
Stale permissions after a role change. The cache TTL defaults to 5 minutes. Set ACL_CACHE_TTL_SECONDS=0 during development or after bulk role changes to force immediate re-evaluation.
Port: 3027 | Pro Plugin — ɳSelf+ | v1.1.1