@iamjs/core
TypeScript icon, indicating that this package has built-in type declarations

2.0.15 • Public • Published

@iamjs/core

iamjs banner

Overview

iamjs is a powerful and flexible library for implementing role-based access control (RBAC) in JavaScript applications. The core package (@iamjs/core) provides essential functionality for managing roles, permissions, and authorization in your application. With iamjs, you can easily define complex permission structures, manage user roles, and enforce access control throughout your application.

Table of Contents

Installation

You can install the iamjs core library using your preferred package manager:

npm install @iamjs/core
# or
yarn add @iamjs/core
# or
pnpm add @iamjs/core
# or
bun add @iamjs/core

Key Concepts

  • Role: A set of permissions that can be assigned to users. Roles define what actions a user can perform on various resources.
  • Resource: An entity in your application that actions can be performed on (e.g., 'user', 'post', 'comment').
  • Action: An operation that can be performed on a resource (e.g., 'create', 'read', 'update', 'delete', 'list').
  • Permission: A combination of a resource and allowed actions. Permissions can be base permissions (CRUD operations) or custom permissions specific to your application.
  • Schema: A collection of roles that defines the overall authorization structure of your application.

Usage

Creating Roles

Create new roles using the Role class. You can define base permissions using CRUD notation and add custom permissions as needed.

import { Role } from '@iamjs/core';

// Create a basic user role
const userRole = new Role({
  name: 'user',
  description: 'Standard user with limited permissions',
  config: {
    user: {
      base: '-r--l', // Can only read and list users
      custom: { 
        updateOwnProfile: true 
      }
    },
    post: {
      base: 'crud-', // Can create, read, update, but not delete posts
      custom: { 
        publish: true,
        unpublish: true
      }
    },
    comment: {
      base: 'crudl', // Full access to comments
      custom: {
        report: true
      }
    }
  }
});

// Create an admin role with full permissions
const adminRole = new Role({
  name: 'admin',
  description: 'Administrator with full access',
  config: {
    user: {
      base: 'crudl',
      custom: { 
        ban: true,
        unban: true
      }
    },
    post: {
      base: 'crudl',
      custom: { 
        publish: true,
        unpublish: true,
        feature: true
      }
    },
    comment: {
      base: 'crudl',
      custom: {
        delete: true,
        restore: true
      }
    }
  }
});

In these examples, we've created two roles: a user role with limited permissions and an admin role with full access. The base permissions use CRUD notation (Create, Read, Update, Delete, List), where a dash (-) indicates the absence of that permission.

Managing Permissions

You can extend or update role permissions using the add and update methods:

// Add a new resource to the user role
const extendedUserRole = userRole.add({
  resource: 'category',
  permissions: {
    base: '-r--l', // Users can only read and list categories
    custom: { 
      subscribe: true,
      unsubscribe: true
    }
  }
});

// Update existing permissions for the admin role
const updatedAdminRole = adminRole.update({
  resource: 'user',
  permissions: {
    base: 'crudl',
    custom: { 
      ban: true,
      unban: true,
      promoteToModerator: true // New custom permission
    }
  }
});

// Remove a resource from a role
const reducedUserRole = userRole.remove({
  resource: 'comment'
});

These methods allow you to dynamically adjust permissions as your application evolves.

Checking Permissions

The Role class provides several methods to check permissions:

// Check if a role can perform a specific action on a resource
console.log(userRole.can('post', 'create')); // true
console.log(userRole.can('user', 'delete')); // false

// Check if a role cannot perform a specific action
console.log(userRole.cannot('user', 'ban')); // true

// Check if a role can perform any of the specified actions
console.log(userRole.canAny('post', ['create', 'delete'])); // true

// Check if a role can perform all of the specified actions
console.log(userRole.canAll('post', ['create', 'read', 'update', 'delete'])); // false

These methods make it easy to implement fine-grained access control in your application logic.

Authorization Management

Use the AuthManager class for centralized authorization management:

import { AuthManager, Schema } from '@iamjs/core';

// Create a schema with multiple roles
const schema = new Schema({ 
  roles: { 
    user: userRole, 
    admin: adminRole,
    moderator: moderatorRole // Assuming you've defined this role
  } 
});

// Initialize the AuthManager with the schema
const auth = new AuthManager(schema);

// Check authorization for different scenarios
console.log(auth.authorize({
  role: 'user',
  actions: ['read', 'create'],
  resources: 'post'
})); // true

console.log(auth.authorize({
  role: 'user',
  actions: ['delete'],
  resources: 'post'
})); // false

console.log(auth.authorize({
  role: 'admin',
  actions: ['ban'],
  resources: 'user'
})); // true

// Check multiple resources at once
console.log(auth.authorize({
  role: 'moderator',
  actions: ['update', 'delete'],
  resources: ['post', 'comment'],
  strict: true // Requires permission for all specified resources
})); // Depends on moderator role definition

The AuthManager provides a convenient way to check permissions across different roles and resources in your application.

API Reference

Role Class

  • constructor(options: RoleOptions)
  • add(options: AddOptions): Role
  • update(options: UpdateOptions): Role
  • remove(options: RemoveOptions): Role
  • can(resource: string, action: string): boolean
  • cannot(resource: string, action: string): boolean
  • canAny(resource: string, actions: string[]): boolean
  • canAll(resource: string, actions: string[]): boolean
  • toObject(): object
  • toJSON(): string
  • static fromObject(obj: object): Role
  • static fromJSON(json: string): Role
  • static from(data: any, transform: Function): Role

AuthManager Class

  • constructor(schema: Schema)
  • authorize(request: AuthorizationRequest): boolean

Schema Class

  • constructor(options: SchemaOptions)
  • getRole(name: string): Role | undefined
  • hasRole(name: string): boolean
  • addRole(role: Role): void
  • removeRole(name: string): void

Advanced Usage

Serialization and Deserialization

Convert roles to and from different formats for storage or transmission:

// Convert a role to JSON
const jsonString = userRole.toJSON();
console.log(jsonString);
// {"name":"user","description":"Standard user with limited permissions","config":{"user":{"base":"-r--l","custom":{"updateOwnProfile":true}},...}}

// Create a role from JSON
const recreatedUserRole = Role.fromJSON(jsonString);

// Convert a role to a plain object
const objectRepresentation = adminRole.toObject();
console.log(objectRepresentation);
// {name: "admin", description: "Administrator with full access", config: {...}}

// Create a role from an object
const recreatedAdminRole = Role.fromObject(objectRepresentation);

Custom Data Transformations

Use the from method for creating roles from custom data sources, such as encrypted data:

import crypto from 'crypto';
import { Role, GetRoleConfig } from '@iamjs/core';

// Assume we have these encryption functions defined
const encrypt = (data: string) => { /* ... */ };
const decrypt = (data: string) => { /* ... */ };

// Encrypt role data for storage
const encryptedRoleData = encrypt(userRole.toJSON());

// Later, recreate the role from encrypted data
const decryptedRole = Role.from(encryptedRoleData, (data) => {
  const decrypted = decrypt(data);
  return Role.fromJSON(decrypted).toObject() as GetRoleConfig<typeof userRole>;
});

console.log(decryptedRole.can('post', 'create')); // true

This approach allows you to securely store and transmit role data while maintaining the ability to recreate functional Role instances.

Best Practices

  1. Granular Permissions: Define permissions at a granular level to allow for fine-tuned access control.
  2. Hierarchical Roles: Consider implementing role hierarchies (e.g., admin > moderator > user) to simplify permission management.
  3. Regular Audits: Periodically review and audit your role definitions to ensure they align with your application's security requirements.
  4. Dynamic Role Assignment: Implement systems to dynamically assign and revoke roles based on user actions or system events.
  5. Principle of Least Privilege: Always start with the minimum necessary permissions and add more as needed.
  6. Consistent Naming: Use consistent naming conventions for resources and actions across your application.
  7. Documentation: Keep your role definitions and permission structures well-documented for easier maintenance and onboarding.

Contributing

We welcome contributions to iamjs! If you'd like to contribute, please follow these steps:

  1. Fork the repository
  2. Create a new branch for your feature or bug fix
  3. Make your changes and write tests if applicable
  4. Submit a pull request with a clear description of your changes

Please see our Contributing Guide for more detailed information.

License

iamjs is released under the MIT License. See the LICENSE file for more details.

Package Sidebar

Install

npm i @iamjs/core

Weekly Downloads

20

Version

2.0.15

License

MIT

Unpacked Size

46.9 kB

Total Files

14

Last publish

Collaborators

  • triyanox