AUTHORIZATION FOR THE ENTIRE TYPESCRIPT STACK
Define permissions once. Enforce them everywhere.
One authorization model for frontend, backend, and database. No extra infrastructure.
import { createMongoAbility, AbilityBuilder } from '@casl/ability';
import { accessibleBy } from '@casl/mongoose';
// Define permissions once
const { can, cannot, build } = new AbilityBuilder(createMongoAbility);
can('read', ['Post', 'Comment']);
can('manage', 'Post', { author: 'me' });
can('create', 'Comment');
const ability = build();
// Enforce them across your application
ability.can('read', 'Post') // UI & API
accessibleBy(ability, 'update').ofType('Post') // Database conditions
By the numbers
Built with CASL
POWERFUL PERMISSIONS. MINIMAL OVERHEAD
Isomorphic
Use the same authorization rules across frontend and backend, with integrations for popular frameworks and ORMs.
Versatile
From simple claim-based checks to action/resource permissions, supporting both RBAC and fine-grained ABAC.
Serializable
Define permissions once. Serialize and share rules across frontend, APIs, and microservices.
TypeSafe
TypeScript-first APIs catch mistakes early and provide a better developer experience.
Tree shakable
Just 6.8kB minified and gzipped, with tree shaking to keep bundles even smaller.
BUILT TO EVOLVE WITH YOUR APPLICATION
Start simple. Scale with complexity.
From basic permissions to roles, attributes, and relationships β using the same authorization model.
Claims
Start with feature access or simple capabilities expressed as actions.
import { AbilityBuilder, createMongoAbility } from '@casl/ability';
const { can, build } = new AbilityBuilder(createMongoAbility);
can('read:project');
can('update:project');
can('manage:workspace');
const ability = build();
ability.can('update:project'); // true
These approaches can coexist. Combine them as your authorization requirements evolve.