Gate
Introduction
The Gate
is the foundation of access control in access-gate
. Think of it as the constitution of your application, containing the rules, guards, and policies that define access permissions. It provides the structure for access control by managing global guards, lazy guards, and policies.
Using the Gate
, you can create Representatives—objects representing entities that are checked for access based on the rules defined in the Gate
.
Core Concepts
-
Building Blocks of Access Control:
- A
Gate
is where all guards, lazy guards, and policies are defined. - It acts as the single source of truth for determining access across your application.
- A
-
Creating Representatives:
- A
Representative
is an object built using the Gate to represent a user, system, or entity being evaluated. - Each
Representative
operates independently, allowing you to evaluate multiple entities against the sameGate
.
- A
-
Global vs. Policy-Specific Guards:
- Global Guards: Applied universally to all access evaluations.
- Policy Guards: Applied only to specific policies during access checks.
-
Execution Flow:
- Guards and policies in the Gate are evaluated in the following order:
- Global Guards: Evaluated when the
Representative
is built. - Lazy Guards: Evaluated during every access (
can()
orcould()
). - Policy Guards: Evaluated during
access()
orasyncAccess()
calls.
- Global Guards: Evaluated when the
- Guards and policies in the Gate are evaluated in the following order:
Using the Gate
1. Create a Gate
Define a Gate to manage policies and guards:
import { Gate } from "access-gate";
const gate = new Gate();
2. Add Guards
Add global guards to the Gate:
gate.guard((representative) => {
if (representative.isAdmin) return true; // Grant access
return undefined; // No decision
});
gate.asyncGuard(async (representative) => {
if (!representative.isActive) return false; // Deny access
return undefined; // No decision
});
3. Add Policies
Attach policies to the Gate to group entity-specific access rules:
import { Policy } from "access-gate";
const userPolicy = new Policy("user");
userPolicy.define("create", (representative) => representative.role === "admin");
userPolicy.define("update", (representative, entity) => {
return representative.id === entity.id || representative.role === "admin";
});
gate.addPolicy(userPolicy);
4. Build Representatives
Create Representatives to evaluate specific entities:
const representative1 = gate.build({ id: 1, role: "user", isAdmin: false });
const representative2 = gate.build({ id: 2, role: "admin", isAdmin: true });
Evaluating Access
1. Basic Access Evaluation
Evaluate access for specific actions on entities:
const access = representative1.access("user", "update");
console.log(access.can({ id: 1 })); // true (self-update allowed)
console.log(access.can({ id: 2 })); // false (not an admin)
2. Async Access Evaluation
Include asynchronous guards in the evaluation:
const asyncAccess = await representative2.asyncAccess("user", "update");
console.log(await asyncAccess.could({ id: 1 })); // true (admin can update)
Detailed Example
import { Gate, Policy } from "access-gate";
// Define a Gate
const gate = new Gate();
// Define a Policy for Posts
const postPolicy = new Policy("post");
postPolicy.define("view", () => true); // Everyone can view
postPolicy.define("edit", (rep, post) => rep.id === post.authorId); // Only owner can edit
// Add Guards
gate.guard((rep) => (rep.isBanned ? false : undefined)); // Block banned users
gate.asyncGuard(async (rep) => {
return rep.isAdmin ? true : undefined; // Admins can bypass other checks
});
// Add Policy to Gate
gate.addPolicy(postPolicy);
// Build Representatives
const user = gate.build({ id: 1, isAdmin: false, isBanned: false });
const admin = gate.build({ id: 2, isAdmin: true, isBanned: false });
// Evaluate Access
console.log(user.access("post", "view").can()); // true
console.log(user.access("post", "edit").can({ authorId: 1 })); // true
console.log(user.access("post", "edit").can({ authorId: 2 })); // false
console.log(admin.access("post", "view").can()); // true
console.log(admin.access("post", "edit").can({ authorId: 2 })); // true (admin override)
Next Steps
Learn more about related components:
- Policy: Understand how policies group access controls for specific entities.
- Guards: Explore how guards influence decisions at global and policy levels.
- Representative: Dive into how representatives interact with the Gate to evaluate access.