Pundit-TS offers a robust solution for organizing authorization logic with type safety. Inspired by the pundit gem, it simplifies role-based and attribute-based access control, ensuring that authorization rules are centralized and easy to manage. Ideal for TypeScript developers seeking clarity in their authorization practices.
Pundit-TS: A Plain TypeScript Authorization Library
Pundit-TS is a robust authorization library designed to help developers organize authorization logic in a fully type-safe manner. Drawing inspiration from the Pundit gem, it offers a seamless way to implement authorization policies across various models and actions.
Key Features
- Type Safety: Pundit-TS ensures all authorization checks are fully type-safe, reducing runtime errors and enhancing developer experience.
- Flexible Models: Supports multiple access control models such as Role-Based Access Control (RBAC), Attribute-Based Access Control (ABAC), and Discretionary Access Control (DAC).
- Easily Declared Actions: Define actions for different entity classes, making it straightforward to manage permissions on models like Users, Posts, and Categories.
- Efficient Filtering: Optimize database queries by applying specific
where
clauses and joins based on user authorization, minimizing unnecessary data retrieval. - Centralized Logic: Keep authorization logic in a single location, enabling reuse and reducing code duplication across your application.
Use Cases
- Confirm user permissions for actions on various entities (e.g., create, update, delete).
- Implement premium user features, such as limiting the number of seats in an organization.
Examples
Pundit-TS caters to different use cases with examples:
- Blog: A simple TypeScript blog example that is not tied to a database, making it a great starting point for newcomers.
- Prisma Blog: An advanced version that utilizes Prisma ORM for database interactions, employing
PostPolicy#filter
to construct arguments forprisma.post.findMany
calls.
Sample Code
Here are some implementation examples demonstrating how to manage access control:
Role-Based Access Control (RBAC)
class Policy {
authorize(ctx, object, action) {
const isAuthenticated = ctx.actor !== null;
const role = ctx.actor?.role;
const isAdmin = role === "admin";
const isEditor = role === "editor";
switch (action) {
case "create":
return isAdmin || isEditor;
case "delete":
return isAdmin;
case "view":
return true; // Accessible to all, including anonymous users
default:
return false; // Disallow other actions
}
}
}
Attribute-Based Access Control (ABAC)
class Policy {
authorize(ctx, object, action) {
if (ctx.actor === null) {
throw new UnauthorizedError();
}
const role = ctx.actor.role;
const isAdmin = role === "admin";
const isEditor = role === "editor";
switch (action) {
case "delete":
return isAdmin;
case "update:content":
return isAdmin || isEditor;
case "view:content":
return true;
default:
return false;
}
}
}
Discretionary Access Control (DAC)
Ideal for multi-tenant applications:
class DocumentPolicy {
authorize(ctx, object, action) {
if (ctx.actor === null) {
return false; // Anonymous users cannot perform any action
}
const isOrganizationOwner = ctx.actor.id === object.organization.owner_id;
if (isOrganizationOwner) {
return true; // Organization owner can perform any action
}
const member = object.organization.members.findById(ctx.actor.id);
if (!member) {
return false;
}
switch (action) {
case "create":
return member.permissions.canCreateDocument;
case "update":
return member.permissions.canUpdateDocument;
default:
return false;
}
}
}
Simple Integration
To get started, create your models and actions, declare your policies, and encapsulate your authorization logic behind your PunditPolicy
implementations. Here is an example:
// Create your Pundit instance:
import { Pundit } from 'pundit-ts';
import { PostPolicy, UserPolicy } from './policies';
const pundit = new Pundit<PolicyContext>()
.register(new UserPolicy())
.register(new PostPolicy());
Once integrated, authorization checks can be performed seamlessly:
const ctx = new PolicyContext();
const post = new Post();
await pundit.authorize(ctx, post, "create");
For more information, visit the Pundit-TS GitHub repository. This library offers developers a comprehensive, type-safe means to manage complex authorization logic.
No comments yet.
Sign in to be the first to comment.