Skip to content

API Reference

createPermission(config)

Creates a permission instance that exposes middleware methods and helper namespaces.

ts
import { createPermission, prismaAdapter } from '@actinode/express-permission'

const permission = createPermission({
  adapter: prismaAdapter(prisma),
  getUserId: (req) => req.user?.id,
})

Config options

OptionTypeDefaultDescription
adapterPermissionAdapterRequired. The database adapter.
getUserId(req: Request) => string | undefinedreq.user?.idExtract 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).

ts
app.get('/posts', permission.can('view-posts'), handler)
ParamTypeDescription
permissionNamestringThe permission to check.

permission.hasRole(roleName)

Passes if the user holds the given role.

ts
app.delete('/users/:id', permission.hasRole('admin'), handler)
ParamTypeDescription
roleNamestringThe role to check.

permission.canAny(permissionNames)

Passes if the user holds at least one of the given permissions.

ts
app.put('/posts/:id', permission.canAny(['edit-posts', 'manage-posts']), handler)
ParamTypeDescription
permissionNamesstring[]At least one must be held.

permission.canAll(permissionNames)

Passes if the user holds every listed permission.

ts
app.post('/posts/:id/publish', permission.canAll(['edit-posts', 'publish-posts']), handler)
ParamTypeDescription
permissionNamesstring[]All must be held.

Error responses

ConditionStatusBody
No userId from getUserId401{ "error": "Unauthorized", "message": "User not authenticated" }
Check fails403{ "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.

ts
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.

ts
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.

ts
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.

ts
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.

ts
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).

ts
const allowed = await permission.check.can(userId, 'edit-posts')

permission.check.hasRole(userId, roleName)

Returns true if the user holds the given role.

ts
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.

ts
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.

ts
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.

ts
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).

ts
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.

ts
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.

ts
await permission.groups.create('content-managers', [
  'view-posts',
  'edit-posts',
  'publish-posts',
])
ParamTypeDescription
namestringGroup name.
permissionsstring[]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.

ts
await permission.groups.assign(userId, 'content-managers')

TypeScript types

ts
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.

ts
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.

ts
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.

Released under the MIT License.