Core Concepts

To effectively use access-gate, it’s essential to understand the core building blocks of the library. These concepts work together to provide a robust and flexible role-based access control (RBAC) system.

1. Gate

The Gate is the central hub that manages policies and guards. It acts as a container for all access control rules.

Key Responsibilities

  • Store and manage policies.
  • Register and evaluate guards.
  • Create Representative instances to evaluate decisions.

Example

import { Gate } from "access-gate";

const gate = new Gate();

// Add policies and guards to the gate
gate.addPolicy(postPolicy);
gate.guard((user) => user.isAdmin);

2. Policies

A Policy defines a set of rules (or actions) for a specific resource. Each action in a policy represents an operation that can be performed, such as “view”, “update”, or “delete”.

Key Methods

  • define(action: string, fn: (user, entity) => boolean): Defines a rule for an action.
  • can(action: string): Evaluates if an action is permitted.

Example

import { Policy } from "access-gate";

// Define a policy for posts
const postPolicy = new Policy("post");

// Define rules for actions
postPolicy.define("view", () => true); // Anyone can view
postPolicy.define("update", (user, post) => user.id === post.authorId); // Only the owner can update

3. Guards

Guards enforce global or contextual restrictions. They work alongside policies to add an extra layer of access control.

Types of Guards

  • Global Guards: Applied to all actions and entities globally and have access only to the representative.
gate.guard((user) => user.isAdmin);
  • Lazy Guards: Applied to specific entities during the call of can() method, and have access to representative and the entity.
gate.lazyGuard((user, post) => user.id === post.authorId);

Async Guards

Guards can also handle asynchronous logic, it’s similar to the global guards.

gate.asyncLazyGuard(async (user, post) => {
  const isOwner = await checkOwnership(user.id, post.id);
  return isOwner;
});

// build the gate using async builder
const representative = await gate.asyncBuild();

4. Decisions

A Decision object represents the result of evaluating policies and guards. It allows you to check whether an action is permitted.

Key Methods

can(): Evaluates a synchronous decision. could(): Evaluates an asynchronous decision.

Example

const decision = representative.access("post", "update").can({ authorId: 1 });
console.log(decision); // true or false

const asyncDecision = await representative
  .access("post", "update")
  .could({ authorId: 2 });
console.log(asyncDecision); // true or false

5. Representative

A Representative evaluates decisions for a specific user. It uses policies and guards registered in the Gate.

Example

const representative = gate.build({ id: 1, role: "user" });

const decision = representative.access("post", "view").can();
console.log(decision); // true or false based on policies and guards

How These Concepts Work Together

  • Define Policies for resources and actions.
  • Register Guards for global or entity-specific restrictions.
  • Use the Gate to manage policies and guards.
  • Create a Representative for the current user.
  • Evaluate Decisions to check access.