API Reference
createPermission(config)
Creates a permission instance that exposes middleware methods and helper namespaces.
import { createPermission, prismaAdapter } from '@actinode/express-permission'
const permission = createPermission({
adapter: prismaAdapter(prisma),
getUserId: (req) => req.user?.id,
})Config options
| Option | Type | Default | Description |
|---|---|---|---|
adapter | PermissionAdapter | — | Required. The database adapter. |
getUserId | (req: Request) => string | undefined | req.user?.id | Extract the user ID from the request. Used by all middleware methods. |
Middleware methods
All middleware methods return an Express RequestHandler. Attach them directly to routes.
permission.can(permissionName)
Passes if the user holds the given permission (direct, via role, or via group).
app.get('/posts', permission.can('view-posts'), handler)| Param | Type | Description |
|---|---|---|
permissionName | string | The permission to check. |
permission.hasRole(roleName)
Passes if the user holds the given role.
app.delete('/users/:id', permission.hasRole('admin'), handler)| Param | Type | Description |
|---|---|---|
roleName | string | The role to check. |
permission.canAny(permissionNames)
Passes if the user holds at least one of the given permissions.
app.put('/posts/:id', permission.canAny(['edit-posts', 'manage-posts']), handler)| Param | Type | Description |
|---|---|---|
permissionNames | string[] | At least one must be held. |
permission.canAll(permissionNames)
Passes if the user holds every listed permission.
app.post('/posts/:id/publish', permission.canAll(['edit-posts', 'publish-posts']), handler)| Param | Type | Description |
|---|---|---|
permissionNames | string[] | All must be held. |
Error responses
| Condition | Status | Body |
|---|---|---|
No userId from getUserId | 401 | { "error": "Unauthorized", "message": "User not authenticated" } |
| Check fails | 403 | { "error": "Forbidden", "message": "..." } |
assign namespace
permission.assign.role(userId, roleName)
Assigns a role to a user. Creates the role if it does not exist. No-op if already assigned.
await permission.assign.role(userId, 'admin')permission.assign.permission(userId, permissionName)
Assigns a direct permission to a user. Creates the permission if it does not exist. No-op if already assigned.
await permission.assign.permission(userId, 'edit-posts')permission.assign.group(userId, groupName)
Assigns a permission group to a user. Throws PermissionError if the group does not exist.
await permission.assign.group(userId, 'content-managers')revoke namespace
permission.revoke.role(userId, roleName)
Removes a role from a user. Throws PermissionError if the role does not exist.
await permission.revoke.role(userId, 'editor')permission.revoke.permission(userId, permissionName)
Removes a direct permission from a user. Throws PermissionError if the permission does not exist.
await permission.revoke.permission(userId, 'delete-posts')check namespace
All check methods return Promise<boolean>.
permission.check.can(userId, permissionName)
Returns true if the user holds the permission via any vector (direct, role, or group).
const allowed = await permission.check.can(userId, 'edit-posts')permission.check.hasRole(userId, roleName)
Returns true if the user holds the given role.
const isAdmin = await permission.check.hasRole(userId, 'admin')permission.check.canAny(userId, permissionNames)
Returns true if the user holds at least one of the permissions.
const canEdit = await permission.check.canAny(userId, ['edit-posts', 'manage-posts'])permission.check.canAll(userId, permissionNames)
Returns true if the user holds every listed permission.
const canPublish = await permission.check.canAll(userId, ['edit-posts', 'publish-posts'])get namespace
permission.get.roles(userId)
Returns all role names assigned to the user.
const roles = await permission.get.roles(userId)
// ['admin', 'editor']Returns Promise<string[]>.
permission.get.permissions(userId)
Returns all direct permission names assigned to the user (not those inherited via roles or groups).
const perms = await permission.get.permissions(userId)
// ['edit-posts', 'view-drafts']Returns Promise<string[]>.
permission.get.groups(userId)
Returns all group names assigned to the user.
const groups = await permission.get.groups(userId)
// ['content-managers']Returns Promise<string[]>.
groups namespace
permission.groups.create(name, permissions)
Creates (or replaces) a permission group with the given permission strings.
await permission.groups.create('content-managers', [
'view-posts',
'edit-posts',
'publish-posts',
])| Param | Type | Description |
|---|---|---|
name | string | Group name. |
permissions | string[] | Permission strings to include in the group. Replaces existing list on update. |
permission.groups.assign(userId, groupName)
Assigns a group to a user. Throws PermissionError if the group does not exist.
await permission.groups.assign(userId, 'content-managers')TypeScript types
interface PermissionConfig {
adapter: PermissionAdapter
getUserId?: (req: Request) => string | undefined
}
interface PermissionAdapter {
assignRole(userId: string, roleName: string): Promise<void>
revokeRole(userId: string, roleName: string): Promise<void>
getRoles(userId: string): Promise<string[]>
hasRole(userId: string, roleName: string): Promise<boolean>
assignPermission(userId: string, permissionName: string): Promise<void>
revokePermission(userId: string, permissionName: string): Promise<void>
getPermissions(userId: string): Promise<string[]>
assignGroup(userId: string, groupName: string): Promise<void>
getGroups(userId: string): Promise<string[]>
createGroup(name: string, permissions: string[]): Promise<void>
can(userId: string, permissionName: string): Promise<boolean>
canAny(userId: string, permissionNames: string[]): Promise<boolean>
canAll(userId: string, permissionNames: string[]): Promise<boolean>
}
type PermissionMiddleware = (req: Request, res: Response, next: NextFunction) => Promise<void>
interface PermissionInstance {
can(permissionName: string): PermissionMiddleware
hasRole(roleName: string): PermissionMiddleware
canAny(permissionNames: string[]): PermissionMiddleware
canAll(permissionNames: string[]): PermissionMiddleware
assign: AssignNamespace
revoke: RevokeNamespace
check: CheckNamespace
get: GetNamespace
groups: GroupsNamespace
}
class PermissionError extends Error {
code: 'NOT_FOUND' | 'UNAUTHORIZED' | 'UNAUTHENTICATED'
}prismaAdapter(prisma)
Creates a Prisma-backed adapter.
import { prismaAdapter } from '@actinode/express-permission'
const adapter = prismaAdapter(prisma)Requires the six models (Role, Permission, PermissionGroup, UserRole, UserPermission, UserGroup) to be present in your Prisma schema. See Getting Started for the full schema.
mongooseAdapter(models)
Creates a Mongoose-backed adapter.
import { mongooseAdapter } from '@actinode/express-permission'
import type { MongooseModels } from '@actinode/express-permission'
const adapter = mongooseAdapter(models)models must satisfy the MongooseModels interface — pass your six Mongoose model instances. See Getting Started for the full setup.
