← All @molecule/* packages · App templates

@molecule/api-permissions

Core interface · permissions · API (Node) · v1.0.1 · Apache-2.0

Permissions core interface for molecule.dev — RBAC/ABAC access control

npm install @molecule/api-permissions

npm · Source on GitHub

How it works

@molecule/api-permissions is the permissions core interface on the API (Node) side: the API your app calls, with no vendor inside.

Choose the implementation by bonding one of its 2 providers: @molecule/api-permissions-casbin, @molecule/api-permissions-custom.

import { setProvider, can, assign } from '@molecule/api-permissions'
import { provider as casbin } from '@molecule/api-permissions-casbin'

setProvider(casbin)

await assign('user:123', 'editor')
const allowed = await can('user:123', 'write', 'project')

Providers (2): @molecule/api-permissions-casbin, @molecule/api-permissions-custom

Works with: @molecule/api-bond, @molecule/api-i18n

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Provider-agnostic permissions interface for molecule.dev.

Defines the PermissionsProvider interface for role-based and attribute-based access control (RBAC/ABAC). Bond packages (Casbin, custom, etc.) implement this interface. Application code uses the convenience functions (can, assign, revoke, getRoles) which delegate to the bonded provider.

Quick Start

import { setProvider, can, assign } from '@molecule/api-permissions'
import { provider as casbin } from '@molecule/api-permissions-casbin'

setProvider(casbin)

await assign('user:123', 'editor')
const allowed = await can('user:123', 'write', 'project')

Type

core

Installation

npm install @molecule/api-permissions @molecule/api-bond @molecule/api-i18n

API

Interfaces

CreateRole

Input for creating a new role.

interface CreateRole {
  /** Human-readable name of the role. */
  name: string

  /** Optional description of the role's purpose. */
  description?: string

  /** Permissions to assign to the role. */
  permissions: Permission[]
}

Permission

A permission granting an action on a resource, optionally with conditions.

interface Permission {
  /** Unique identifier for this permission. */
  id: string

  /** The action this permission grants (e.g. `read`, `write`, `delete`). */
  action: string

  /** The resource this permission applies to (e.g. `project`, `user`, `*`). */
  resource: string

  /** Optional ABAC conditions that must be met for this permission to apply. */
  conditions?: Record<string, unknown>
}

PermissionsProvider

Permissions provider interface.

All permissions providers must implement this interface to provide authorization checking, role management, and permission assignment.

interface PermissionsProvider {
  /**
   * Checks whether a subject is allowed to perform an action on a resource.
   *
   * @param subject - The entity requesting access (e.g. user ID).
   * @param action - The action being requested (e.g. `read`, `write`).
   * @param resource - The resource being accessed (e.g. `project`).
   * @param context - Optional ABAC context attributes for condition evaluation.
   * @returns `true` if the subject is authorized.
   */
  can(
    subject: string,
    action: string,
    resource: string,
    context?: Record<string, unknown>,
  ): Promise<boolean>

  /**
   * Assigns a role to a subject, optionally within a scope.
   *
   * @param subject - The entity to assign the role to.
   * @param role - The role name to assign.
   * @param scope - Optional scope for the assignment (e.g. `org:123`).
   */
  assign(subject: string, role: string, scope?: string): Promise<void>

  /**
   * Revokes a role from a subject, optionally within a scope.
   *
   * @param subject - The entity to revoke the role from.
   * @param role - The role name to revoke.
   * @param scope - Optional scope for the revocation.
   */
  revoke(subject: string, role: string, scope?: string): Promise<void>

  /**
   * Retrieves all roles assigned to a subject.
   *
   * @param subject - The entity to look up roles for.
   * @returns The roles assigned to the subject.
   */
  getRoles(subject: string): Promise<Role[]>

  /**
   * Creates a new role definition.
   *
   * @param role - The role definition to create.
   * @returns The created role with an assigned `id`.
   */
  createRole(role: CreateRole): Promise<Role>

  /**
   * Deletes a role definition by ID.
   *
   * @param roleId - The ID of the role to delete.
   */
  deleteRole(roleId: string): Promise<void>

  /**
   * Retrieves all permissions granted by a role.
   *
   * @param role - The role name to look up permissions for.
   * @returns The permissions granted by the role.
   */
  getPermissions(role: string): Promise<Permission[]>

  /**
   * Adds a permission to an existing role.
   *
   * @param role - The role name to add the permission to.
   * @param permission - The permission to add.
   */
  addPermission(role: string, permission: Permission): Promise<void>

  /**
   * Removes a permission from a role.
   *
   * @param role - The role name to remove the permission from.
   * @param permissionId - The ID of the permission to remove.
   */
  removePermission(role: string, permissionId: string): Promise<void>
}

Role

A role grouping one or more permissions, optionally scoped.

interface Role {
  /** Unique identifier for this role. */
  id: string

  /** Human-readable name of the role (e.g. `admin`, `editor`). */
  name: string

  /** Optional description of the role's purpose. */
  description?: string

  /** Permissions granted by this role. */
  permissions: Permission[]

  /** Optional scope restricting where this role applies (e.g. `org:123`). */
  scope?: string
}

Functions

addPermission(role, permission)

Adds a permission to an existing role.

function addPermission(role: string, permission: Permission): Promise<void>
  • role — The role name to add the permission to.
  • permission — The permission to add.

Returns: Resolves when the permission is attached to the role.

assign(subject, role, scope)

Assigns a role to a subject, optionally within a scope.

function assign(subject: string, role: string, scope?: string): Promise<void>
  • subject — The entity to assign the role to.
  • role — The role name to assign.
  • scope — Optional scope for the assignment (e.g. org:123).

Returns: Resolves when the bonded provider records the assignment.

can(subject, action, resource, context)

Checks whether a subject is allowed to perform an action on a resource.

function can(
  subject: string,
  action: string,
  resource: string,
  context?: Record<string, unknown>,
): Promise<boolean>
  • subject — The entity requesting access (e.g. user ID).
  • action — The action being requested (e.g. read, write).
  • resource — The resource being accessed (e.g. project).
  • context — Optional ABAC context attributes for condition evaluation.

Returns: true if the subject is authorized.

createRole(role)

Creates a new role definition.

function createRole(role: CreateRole): Promise<Role>
  • role — The role definition to create.

Returns: The created role with an assigned id.

deleteRole(roleId)

Deletes a role definition by ID.

function deleteRole(roleId: string): Promise<void>
  • roleId — The ID of the role to delete.

Returns: Resolves when the role is removed.

getPermissions(role)

Retrieves all permissions granted by a role.

function getPermissions(role: string): Promise<Permission[]>
  • role — The role name to look up permissions for.

Returns: The permissions granted by the role.

getProvider()

Retrieves the bonded permissions provider, throwing if none is configured.

function getProvider(): PermissionsProvider

Returns: The bonded permissions provider.

getRoles(subject)

Retrieves all roles assigned to a subject.

function getRoles(subject: string): Promise<Role[]>
  • subject — The entity to look up roles for.

Returns: The roles assigned to the subject.

hasProvider()

Checks whether a permissions provider is currently bonded.

function hasProvider(): boolean

Returns: true if a permissions provider is bonded.

removePermission(role, permissionId)

Removes a permission from a role.

function removePermission(role: string, permissionId: string): Promise<void>
  • role — The role name to remove the permission from.
  • permissionId — The ID of the permission to remove.

Returns: Resolves when the permission is removed from the role.

revoke(subject, role, scope)

Revokes a role from a subject, optionally within a scope.

function revoke(subject: string, role: string, scope?: string): Promise<void>
  • subject — The entity to revoke the role from.
  • role — The role name to revoke.
  • scope — Optional scope for the revocation.

Returns: Resolves when the bonded provider records the revocation.

setProvider(provider)

Registers a permissions provider as the active singleton. Called by bond packages during application startup.

function setProvider(provider: PermissionsProvider): void
  • provider — The permissions provider implementation to bond.

Available Providers

ProviderPackage
Casbin (RBAC)@molecule/api-permissions-casbin
Custom (in-memory RBAC/ABAC)@molecule/api-permissions-custom

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-bond ^1.0.1
  • @molecule/api-i18n ^1.0.1

Runtime Dependencies

  • @molecule/api-bond
  • @molecule/api-i18n

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:

  • A user whose role HAS a permission can perform the gated action through the UI; a user whose role lacks it cannot.
  • Denial is enforced SERVER-SIDE: attempting the gated action anyway (or reloading after the attempt) shows nothing changed — hiding the button alone is not enforcement.
  • Role-gated screens/navigation are unreachable for unauthorized roles (redirect or clear denial — never a blank page or leaked data).
  • Assigning a role through the app's admin surface grants the new abilities, and revoking it removes them.
  • The same checks hold against OWNED resources: a permitted role still cannot act on another user's private records unless the app intends it.