AUTHORIZATION FOR THE ENTIRE TYPESCRIPT STACK

Define permissions once. Enforce them everywhere.

One authorization model for frontend, backend, and database. No extra infrastructure.

Why CASL?

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

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.

01 / A CAPABILITY

Claims

Start with feature access or simple capabilities expressed as actions.

A stable API for simple permissions, ready to gain resource context when you need it.
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.