Vai al contenuto principale

Casbin vs. CASL

CASL and Casbin are the two authorization libraries JavaScript developers compare most often. CASL is written for JavaScript and TypeScript and defines permissions in code. Casbin keeps permissions outside the code as a model and policy rules, and the same rules run in Node.js, the browser, and other languages.

Summary​

CasbinCASL
LanguagesNode.js and browser, plus Go, Java, Python, .NET, PHP, Rust, C++, and moreJavaScript and TypeScript
How rules are writtenA model file plus policy rules as rowscan and cannot calls in code, or rule objects in JSON
Typical rulep, editor, article, writecan('update', 'Article', { authorId: user.id })
RolesBuilt in: role assignment, hierarchies, per-tenant rolesYou map roles to abilities in your own code
Rule storageDatabase adapters (Sequelize, TypeORM, Prisma, Mongoose, and others)You store and load rules yourself
Frontendcasbin.js receives the user's permissions from the backendPackages for React, Vue, and Angular
Database query filteringThrough the policy and your own queriesHelpers that turn conditions into Prisma or Mongoose queries
Governance and licenseApache Software Foundation (Incubating), Apache-2.0Community project, MIT

Rules in code versus rules as data​

A CASL ability is built in code for the current user:

import { AbilityBuilder, createMongoAbility } from "@casl/ability";

function defineAbilityFor(user) {
const { can, build } = new AbilityBuilder(createMongoAbility);
can("read", "Article");
if (user.role === "editor") {
can("update", "Article", { authorId: user.id });
}
return build();
}

This is easy to read, type-safe in TypeScript, and convenient when the rules are fixed and known to developers. Changing who may do what means changing and redeploying code, unless you build your own storage for rule objects.

Casbin separates the two parts. The model describes the shape of a rule and is written once:

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

The rules are data:

p, reader, article, read
p, editor, article, update
g, alice, editor

An administrator can add a role or a permission at runtime through the Management API, and the change is saved to your database by an adapter. Ownership rules such as "editors update only their own articles" are written in the matcher with ABAC: r.sub == r.obj.authorId.

Frontend​

CASL is strong in the browser. Its React, Vue, and Angular packages make it simple to show or hide buttons, and the same ability object can be used on both sides.

With Casbin, the server remains the source of truth. It sends the current user's permissions to the browser, where casbin.js answers can questions for UI components. The frontend never holds other users' rules.

More than one language​

CASL covers JavaScript. If part of your backend is written in Go, Java, or Python, those services need a different authorization library and a second copy of the rules.

A Casbin model and policy are language-neutral. A Node.js API, a Go worker, and a Python service can load the same policy from the same database and reach the same decisions.

When to choose which​

Choose CASL if your stack is entirely JavaScript or TypeScript, permissions are defined by developers and rarely change at runtime, and you want tight integration with UI frameworks and with Prisma or Mongoose queries.

Choose Casbin if administrators manage roles and permissions at runtime, you need role hierarchies or multi-tenant roles out of the box, your rules should live in a database, or several services in different languages must enforce the same policy.

Try Casbin​

Follow the Node.js and Express tutorial, or test a model and policy in the online editor.

See also the comparison overview.