### Quick Start with AbilityProvider, Can, and useAbility Source: https://github.com/stalniy/casl/blob/master/packages/casl-react/README.md Demonstrates basic setup using AbilityProvider to wrap the app, Can for declarative rendering, and useAbility for imperative checks. ```tsx import { createMongoAbility } from '@casl/ability'; import { AbilityProvider, Can, useAbility } from '@casl/react'; const ability = createMongoAbility([ { action: 'read', subject: 'Post' }, { action: 'create', subject: 'Post' }, ]); export function App() { return (
List of posts
); } function CreatePostButton() { const ability = useAbility(); return ability.can('create', 'Post') && ( ); } ``` -------------------------------- ### Setup Development Environment Source: https://github.com/stalniy/casl/blob/master/CONTRIBUTING.md Commands to clone the repository, install dependencies using pnpm, and build the project packages. ```sh # replace ${YOUR_GITHUB_USER_NAME} with your github username git clone git@github.com:${YOUR_GITHUB_USER_NAME}/casl.git # install pnpm, other ways at https://pnpm.js.org/en/installation npx pnpm add -g pnpm cd casl pnpm i -r pnpm run -r build # build all packages so local deps can be linked ``` -------------------------------- ### Install @casl/ability with npm Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/install/en.md Use npm to install the core CASL ability package. This is the recommended method for most projects. ```sh npm install @casl/ability ``` -------------------------------- ### Install CASL Prisma and Ability Source: https://github.com/stalniy/casl/blob/master/packages/casl-prisma/README.md Install the necessary CASL packages for Prisma integration and core ability management. ```sh npm install @casl/prisma @casl/ability # or yarn add @casl/prisma @casl/ability # or pnpm add @casl/prisma @casl/ability ``` -------------------------------- ### Install CASL Vue Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/package/casl-vue/en.md Install the CASL Vue package using npm or yarn. ```bash npm install @casl/vue ``` ```bash yarn add @casl/vue ``` -------------------------------- ### Install CASL Vue and Ability Source: https://github.com/stalniy/casl/blob/master/packages/casl-vue/README.md Install the necessary packages for CASL Vue integration using npm, yarn, or pnpm. ```sh npm install @casl/vue @casl/ability # or yarn add @casl/vue @casl/ability # or pnpm add @casl/vue @casl/ability ``` -------------------------------- ### Field Pattern Examples Table Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/restricting-fields/en.md This table illustrates the behavior of various field patterns, including '*', '**', and combinations thereof, with examples of how they match nested field names. ```plaintext Pattern | Example | Result | | --------------- | -------------| --------- | | address.* | | | `ability.can('read', 'User', 'address')` | `true` | | | `ability.can('read', 'User', 'address.city')` | `true` | | | `ability.can('read', 'User', 'address.city.name')` | `false` | ad dress.** | | | `ability.can('read', 'User', 'address')` | `true` | | | `ability.can('read', 'User', 'address.city')` | `true` | | | `ability.can('read', 'User', 'address.city.name')` | `true` | | | `ability.can('read', 'User', 'address.city.location.lat')` | `true` | | address.*.name | | | `ability.can('read', 'User', 'address.*.name')` | `true` | | | `ability.can('read', 'User', 'address.city.name')` | `true` | | | `ability.can('read', 'User', 'address.city.location.name')` | `false` | | address.**.name | | | `ability.can('read', 'User', 'address.*.name')` | `true` | | | `ability.can('read', 'User', 'address.city.name')` | `true` | | | `ability.can('read', 'User', 'address.city.location.name')` | `true` | | *.name | | | `ability.can('read', 'User', '*.name')` | `true` | | | `ability.can('read', 'User', 'city.name')` | `true` | | | `ability.can('read', 'User', 'address.city.name')` | `false` | | | `ability.can('read', 'User', 'address.city.location.name')` | `false` | | **.name | | | `ability.can('read', 'User', '*.name')` | `true` | | | `ability.can('read', 'User', 'city.name')` | `true` | | | `ability.can('read', 'User', 'address.city.name')` | `true` | | | `ability.can('read', 'User', 'address.city.location.name')` | `true` | | | `ability.can('read', 'User', 'address.city.code')` | `false` | ``` -------------------------------- ### Install CASL Mongoose Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/package/casl-mongoose/en.md Install the package via npm. ```bash npm install @casl/mongoose ``` -------------------------------- ### Install @casl/ability with yarn Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/install/en.md Use yarn to install the core CASL ability package. This is an alternative to npm. ```sh yarn add @casl/ability ``` -------------------------------- ### Install CASL React and Ability Source: https://github.com/stalniy/casl/blob/master/packages/casl-react/README.md Install the necessary CASL packages for React integration and ability management. ```sh npm install @casl/react @casl/ability # or yarn add @casl/react @casl/ability # or pnpm add @casl/react @casl/ability ``` -------------------------------- ### Install @casl/angular and @casl/ability Source: https://github.com/stalniy/casl/blob/master/packages/casl-angular/README.md Install the necessary CASL packages for Angular integration using npm, yarn, or pnpm. ```sh npm install @casl/angular @casl/ability # or yarn add @casl/angular @casl/ability # or pnpm add @casl/angular @casl/ability ``` -------------------------------- ### Install CASL Vue 1.x for Vue 2.x Source: https://github.com/stalniy/casl/blob/master/packages/casl-vue/README.md Install version 1.x of @casl/vue for compatibility with Vue 2.x applications. ```sh npm install @casl/vue@1.x @casl/ability # or yarn add @casl/vue@1.x @casl/ability # or pnpm add @casl/vue@1.x @casl/ability ``` -------------------------------- ### Check User Permissions Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/intro/en.md Check user permissions against defined abilities. This example demonstrates checking read, update, and delete permissions for 'Post' and 'User' subjects. ```javascript import ability from './defineAbility.js'; ability.can('read', 'Post') // true ability.can('read', 'User') // true ability.can('update', 'User') // true ability.can('delete', 'User') // false ability.cannot('delete', 'User') // true ``` -------------------------------- ### Initial Database Migration (SQLite) Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/roles-with-persisted-permissions/en.md Defines the schema for users, articles, and roles tables, including foreign key constraints. This script is used with Knex.js for database setup. ```js exports.up = function(knex) { return knex.schema .createTable('users', (table) => { table.increments('id'); table.string('email', 255).notNullable(); table.string('password', 50).notNullable(); table.integer('roleId').unsigned().notNullable(); table.foreign('roleId').references('id').inTable('roles'); }) .createTable('articles', (table) => { table.increments('id'); table.string('title', 255).notNullable(); table.string('description').notNullable(); table.integer('authorId').unsigned().notNullable(); table.foreign('authorId').references('id').inTable('users'); }) .createTable('roles', (table) => { table.increments('id'); table.string('name', 255).notNullable(); table.json('permissions').notNullable(); }); }; exports.down = function(knex) { return knex.schema .dropTable('users') .dropTable('articles') .dropTable('roles'); }; ``` -------------------------------- ### Install CASL Mongoose and Ability Source: https://github.com/stalniy/casl/blob/master/packages/casl-mongoose/README.md Install the necessary CASL packages for Mongoose integration and ability definition. ```sh npm install @casl/mongoose @casl/ability # or yarn add @casl/mongoose @casl/ability # or pnpm add @casl/mongoose @casl/ability ``` -------------------------------- ### Install @casl/ability with pnpm Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/install/en.md Use pnpm to install the core CASL ability package. This is another alternative package manager. ```sh pnpm add @casl/ability ``` -------------------------------- ### Install CASL Angular package Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/package/casl-angular/en.md Use npm to install the package in your Angular project. ```bash npm install @casl/angular @casl/ability ``` -------------------------------- ### Define User Abilities Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/intro/en.md Define user abilities using `can` and `cannot` functions. This example permits all actions on all subjects but forbids deleting users. ```javascript import { defineAbility } from '@casl/ability'; export default defineAbility((can, cannot) => { can('manage', 'all'); cannot('delete', 'User'); }); ``` -------------------------------- ### Build CASL from Source Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/install/en.md Use this command to clone the CASL repository, install dependencies, and build the CASL package from the latest source code. This is necessary if you need to use CASL directly from GitHub. ```sh git clone git@github.com:stalniy/casl.git cd casl pnpm i -r cd packages/casl-ability npm run build ``` -------------------------------- ### Fetch Accessible Records for a Different Action Source: https://github.com/stalniy/casl/blob/master/packages/casl-mongoose/README.md Fetches records accessible for an action other than the default 'read'. This example retrieves posts that the user can 'update'. ```javascript const Post = require('./Post'); const ability = require('./ability'); async function main() { const postsThatCanBeUpdated = await Post.accessibleBy(ability, 'update'); console.log(postsThatCanBeUpdated); } ``` -------------------------------- ### Manual Claim Check Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/claim-authorization/en.md A basic JavaScript example demonstrating how to check for permissions by manually including claims in a user object. This approach requires explicit testing and maintenance for each permission check. ```typescript const ACTIONS = ['review', 'publish', 'read']; function publishArticle(article, user) { if (!user.permissions.includes('publish')) { throw new Error('You cannot publish articles'); } // logic to publish article } ``` -------------------------------- ### Infer Subject Types from Interfaces Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/typescript/en.md Define actions and subjects using TypeScript interfaces. This example demonstrates how to create an ability instance and includes examples of correct and incorrect usage that would result in build-time errors. ```typescript import { createMongoAbility } from '@casl/ability'; interface Article { id: number title: string content: string authorId: number } interface User { id: number name: string } interface Comment { id: number content: string authorId: number } type Action = 'create' | 'read' | 'update' | 'delete'; type Subject = Article | Comment | User | 'Article' | 'User' | 'Comment'; const ability = createMongoAbility<[Action, Subject]>(); ability.can('read', 'Article'); ability.can('write', 'Article'); // error because non-existing action name ability.can('update', 'Coment') // error because of typo ``` -------------------------------- ### Fetch Accessible Articles using Static Method Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/ability-to-database-query/en.md This example demonstrates how to use the `accessibleBy` static method on the `Article` model to fetch records that the current user has permission to read. It initializes Sequelize, defines the Article model, creates an ability, and then calls `Article.accessibleBy`. ```javascript const { Sequelize } = require('sequelize'); const { defineAbility } = require('@casl/ability'); const defineArticle = require('./Article'); const sequelize = new Sequelize('sqlite::memory'); const Article = defineArticle(sequelize); async function main() { const ability = defineAbility(can => can('read', Article, { published: true })); const articles = await Article.accessibleBy(ability); console.log(articles); } main().catch(console.error); ``` -------------------------------- ### Define Basic Rules with defineAbility Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/define-rules/en.md Use the `defineAbility` function for simple rule definitions, suitable for unit tests, examples, and prototypes. It accepts `can` and `cannot` functions to declare permissions. ```javascript import { defineAbility } from '@casl/ability'; export default defineAbility((can, cannot) => { can('read', 'Post'); cannot('delete', 'Post', { published: true }); }); ``` -------------------------------- ### Check Article Permissions Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/intro/en.md Check permissions for various scenarios using a CASL ability instance. This example demonstrates checking read and update permissions on specific fields and articles. ```javascript import defineAbilityFor from './defineAbility'; import { Article } from './entities'; const moderator = { id: 2, isModerator: true }; const ownArticle = new Article({ authorId: moderator.id }); const foreignArticle = new Article({ authorId: 10 }); const ability = defineAbilityFor(moderator); ability.can('read', 'Article') // true ability.can('update', 'Article', 'published') // true ability.can('update', ownArticle, 'published') // true ability.can('update', foreignArticle, 'title') // false ``` -------------------------------- ### Casl Ability Setup with TypeScript Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/roles-with-persisted-permissions/en.md Defines available actions and subjects for Casl abilities and provides a typed factory function for creating ability instances. Uses TypeScript for enhanced type safety. ```ts import { createMongoAbility, MongoAbility, RawRuleOf, ForcedSubject } from '@casl/ability'; export const actions = ['manage', 'create', 'read', 'update', 'delete'] as const; export const subjects = ['Article', 'all'] as const; export type Abilities = [ typeof actions[number], typeof subjects[number] | ForcedSubject> ]; export type AppAbility = MongoAbility; export const createAbility = (rules: RawRuleOf[]) => createMongoAbility(rules); ``` -------------------------------- ### Updating Ability Instance on User Login Source: https://github.com/stalniy/casl/blob/master/packages/casl-react/README.md This example demonstrates how to update the CASL `Ability` instance when a user logs in, based on their role. It uses `fetch` to log in and then calls `updateAbility` to apply new rules. ```typescript import { AbilityBuilder, Ability } from '@casl/ability'; import React, { useState } from 'react'; import { useAbility } from '@casl/react'; function updateAbility(ability, user) { const { can, rules } = new AbilityBuilder(Ability); if (user.role === 'admin') { can('manage', 'all'); } else { can('read', 'all'); } ability.update(rules); } export default () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const ability = useAbility(); const login = () => { const params = { method: 'POST', body: JSON.stringify({ username, password }) }; return fetch('path/to/api/login', params) .then(response => response.json()) .then(({ user }) => updateAbility(ability, user)); }; return (
{/* input fields */}
); }; ``` -------------------------------- ### Define Ability with Inverted Rule Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/define-rules/en.md This example demonstrates how to define an ability that uses an inverted rule to explicitly forbid an action based on a condition, such as a user not having a paid subscription. ```javascript import { AbilityBuilder, createMongoAbility } from '@casl/ability'; async function defineAbility(user) { const hasPaidSubscription = await user.hasPaidSubscription(); const { can, cannot, build } = new AbilityBuilder(createMongoAbility); if (hasPaidSubscription) { can('create', 'BlogPost'); } else { cannot('create', 'BlogPost').because('You have not paid for monthly subscription'); } return build() } ``` -------------------------------- ### Infer Subject Types from Classes Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/typescript/en.md Define actions and subjects using TypeScript classes. This example shows how to create an ability instance and use it with class instances and class references. ```typescript import { createMongoAbility } from '@casl/ability'; class Article { id: number title: string content: string authorId: number } type Action = 'create' | 'read' | 'update' | 'delete'; type Subject = typeof Article | Article; const ability = createMongoAbility<[Action, Subject]>(); ability.can('read', Article); ability.can('update', new Article()); ``` -------------------------------- ### Test Rule Distribution Logic (Incorrect Approach) Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/debugging-testing/en.md This example demonstrates an incorrect way to test CASL permissions by directly checking the generated rules. This approach is brittle and prone to breaking when rules are refactored. ```javascript import { defineRulesFor } from './defineAbility'; describe('Permissions', () => { let user; describe('when user is an admin', () => { beforeEach(() => { user = { isAdmin: true }; }); it('can do anything', () => { expect(defineRulesFor(user)).to.deep.equal([ { action: 'manage', subject: 'all' } ]); }); }); describe('when user is a regular user', () => { beforeEach(() => { user = { isRegular: true }; }); it('can read non private article', () => { expect(defineRulesFor(user)).to.deep.contain([ { action: 'read', subject: 'Article' }, { action: 'read', subject: 'Article', conditions: { private: true }, inverted: true } ]); }); }); }); ``` -------------------------------- ### Common MongoDB Query Operator Examples Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/conditions-in-depth/en.md Provides a collection of various query patterns including equality, existence checks, range filtering, array matching, and regex patterns for property validation. ```javascript const queries = [ { private: true }, { private: false, hidden: false }, { private: { $exists: true } }, { status: { $in: ['review', 'inProgress'] } }, { price: { $gte: 10, $lte: 50 } }, { tags: { $all: ['permission', 'casl'] } }, { email: { $regex: /@gmail.com$/i } }, { 'cities.address': { $elemMatch: { postalCode: { $regex: /^AB/ } } } } ] ``` -------------------------------- ### Safer Permissions Inference with Dependencies Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/typescript/en.md Define explicit dependencies between actions and subjects for enhanced type safety. This example demonstrates how to restrict actions on certain subjects, leading to build-time errors for disallowed operations. ```typescript import { createMongoAbility } from '@casl/ability'; type CRUD = 'create' | 'read' | 'update' | 'delete'; type Abilities = ['read', 'User'] | [CRUD, 'Article']; const ability = createMongoAbility(); ability.can('read', 'User'); ability.can('create', 'User'); // build time error! because it's not allowed to create users ``` -------------------------------- ### Allow Access to Fields Matching a Prefix with '*' Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/restricting-fields/en.md Use a pattern like 'street*' to grant access to fields that start with a specific prefix. This is helpful when a resource has multiple fields with similar naming conventions, such as 'street1', 'street2', etc. ```javascript import { defineAbility } from '@casl/ability'; const ability = defineAbility((can) => { can('read', 'User', ['street*']); }); ability.can('read', 'User', 'street'); // true ability.can('read', 'User', 'street1'); // true ability.can('read', 'User', 'street2'); // true ``` -------------------------------- ### Initial Database Migration Script Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/roles-with-static-permissions/en.md Sets up the 'users' and 'roles' tables for the application. The 'users' table includes foreign key constraint to the 'roles' table. ```javascript exports.up = function(knex) { return knex.schema .createTable('users', (table) => { table.increments('id'); table.string('email', 255).notNullable(); table.string('password', 50).notNullable(); table.integer('roleId').unsigned().notNullable(); table.foreign('roleId').references('id').inTable('roles'); }) .createTable('roles', (table) => { table.increments('id'); table.string('name', 255).notNullable(); }); }; exports.down = function(knex) { return knex.schema .dropTable('users') .dropTable('roles'); }; ``` -------------------------------- ### Instantiate Ability with Rules Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/api/casl-ability/en.md Create a new Ability instance and initialize it with a set of permission rules. This is useful for setting up initial permissions. ```typescript const ability = new Ability<['read' | 'update', 'Article']>([ { action: 'read', subject: 'Article' }, { action: 'update', subject: 'Article' }, ]); ``` -------------------------------- ### Check Permissions in Application Logic Source: https://github.com/stalniy/casl/blob/master/packages/casl-ability/README.md Shows how to verify user permissions against specific actions or objects using the ability instance, and how to enforce them by throwing errors. ```javascript import { BlogPost, ForbiddenError } from '../models'; const user = getLoggedInUser(); const ability = defineAbilitiesFor(user); ability.can('read', 'BlogPost'); const post = new BlogPost({ title: 'What is CASL?' }); ability.cannot('read', post); ForbiddenError.from(ability).throwUnlessCan('read', post); ``` -------------------------------- ### Initial Database Seed Script Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/roles-with-static-permissions/en.md Populates the 'roles' table with 'admin' and 'member' roles and seeds the 'users' table with initial admin and member user records. ```javascript exports.seed = async (knex) => { await Promise.all([ knex('users').del(), knex('roles').del() ]); await knex('roles').insert([ { id: 1, name: 'admin' }, { id: 2, name: 'member' } ]); await knex('users').insert([ { id: 1, email: 'admin@casl.io', password: '123456', roleId: 1 }, { id: 2, email: 'member@casl.io', password: '123456', roleId: 2 }, ]); }; ``` -------------------------------- ### Initial Database Seed Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/roles-with-persisted-permissions/en.md Populates the database with initial roles (admin, member) and users. Permissions are stored as JSON strings, with dynamic conditions for member articles. ```js exports.seed = async (knex) => { await Promise.all([ knex('users').del(), knex('roles').del() ]); await knex('roles').insert([ { id: 1, name: 'admin', permissions: JSON.stringify([ { action: 'manage', subject: 'all' } ]) }, { id: 2, name: 'member', permissions: JSON.stringify([ { action: 'read', subject: 'Article' }, { action: 'manage', subject: 'Article', conditions: { authorId: '${user.id}' } }, ]) } ]); await knex('users').insert([ { id: 1, email: 'admin@casl.io', password: '123456', roleId: 1 }, { id: 2, email: 'member@casl.io', password: '123456', roleId: 2 }, ]); }; ``` -------------------------------- ### Fetch Users and Create Abilities Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/roles-with-persisted-permissions/en.md Fetches admin and author users and creates CASL Ability instances for each based on their permissions. Ensure user fetching and ability creation services are correctly implemented. ```typescript import { findBy } from './services/users'; import { createAbility } from './services/appAbility'; export default async function main() { const [admin, author] = await Promise.all([ findBy({ email: 'admin@casl.io' }), findBy({ email: 'member@casl.io' }), ]); const adminAbility = createAbility(admin!.permissions); const authorAbility = createAbility(author!.permissions); // the rest of the code } ``` -------------------------------- ### Ability Constructor Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/api/casl-ability/en.md Initializes a new instance of the Ability class. It accepts an array of rules and an options object for customizing behavior like subject type detection, condition matching, field matching, and action alias resolution. ```APIDOC ## Ability Constructor ### Description Initializes a new instance of the Ability class. It accepts an array of rules and an options object for customizing behavior like subject type detection, condition matching, field matching, and action alias resolution. ### Parameters * `rules`: `RawRuleFrom[]` - An array of raw rules to initialize the ability with. Defaults to an empty array. * `options`: `AbilityOptions` - An optional object for configuration: * `detectSubjectType`: `(subject?: Subject) => string` - A function to detect the subject type. * `conditionsMatcher`: `ConditionsMatcher` - A function to customize condition matching logic. * `fieldMatcher`: `FieldMatcher` - A function to customize field matching logic. * `resolveAction`: `ResolveAction[0]>` - A function to resolve action aliases. ### Usage ```ts import { Ability } from '@casl/ability'; const ability = new Ability<['read' | 'update', 'Article']>([ { action: 'read', subject: 'Article' }, { action: 'update', subject: 'Article' }, ]); ``` ### See also * [Define rules](../../guide/define-rules) ``` -------------------------------- ### Can Component with Field Check Source: https://github.com/stalniy/casl/blob/master/packages/casl-react/README.md Example of using the Can component to check permissions for a specific field within a subject. ```jsx export default ({ post }) => Yes, you can do this! ;) ``` -------------------------------- ### Find User by Conditions and Prepare Permissions Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/roles-with-persisted-permissions/en.md Fetches a user from the database based on provided conditions and interpolates their permissions. This function prepares user permissions for direct use with `createAbility`. ```typescript import db from '../db'; import { User } from '../models/User'; import interpolate from '../helpers/interpolate'; export async function findBy(where: Partial>) { const { permissions, ...user } = await db('users') .innerJoin('roles', 'users.roleId', 'roles.id') .select('users.id', 'users.email', 'roles.permissions', { role: 'roles.name' }) .where(where) .first(); user.permissions = interpolate(permissions, { user }); return user; } ``` -------------------------------- ### Can Component with React Element Children Source: https://github.com/stalniy/casl/blob/master/packages/casl-react/README.md Example of using standard React elements as children for the Can component for simple conditional rendering. ```jsx export default () => ``` -------------------------------- ### Define Ability Instance Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/package/casl-vue/en.md Create an instance of the `Ability` class and define rules for authorization. ```javascript import { AbilityBuilder } from '@casl/ability'; function defineAbilitiesFor(user) { const { can, build } = new AbilityBuilder(Ability); if (user.isAdmin) { can('manage', 'all'); } else { can('read', 'all'); } return build(); } export default defineAbilitiesFor; ``` -------------------------------- ### Define User Abilities with CASL Source: https://github.com/stalniy/casl/blob/master/packages/casl-ability/README.md Demonstrates how to use AbilityBuilder to define granular permissions, including conditional rules based on user ownership and time-based constraints. ```javascript import { AbilityBuilder, createMongoAbility } from '@casl/ability'; import { User } from '../models'; function defineAbilitiesFor(user) { const { can, cannot, build } = new AbilityBuilder(createMongoAbility); can('read', 'BlogPost'); can('manage', 'BlogPost', { author: user.id }); cannot('delete', 'BlogPost', { createdAt: { $lt: Date.now() - 24 * 60 * 60 * 1000 } }); return build(); } ``` -------------------------------- ### Express Session Configuration with Redis Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/cache-rules/en.md Configures express-session with a Redis store for session management. This setup is necessary when using session storage for CASL rules. ```typescript import { provideAbility } from './provideAbility'; import express from 'express'; import session from 'express-session'; import redis from 'redis'; import createRedisStore from 'connect-redis'; const app = express(); const RedisStore = createRedisStore(session); app.use(session({ store: new RedisStore({ client: redis.createClient() }), secret: 'my app session secret', })); // app configuration and other middlewares app.use(provideAbility); ``` -------------------------------- ### Provide Ability Instance with AbilityProvider Source: https://github.com/stalniy/casl/blob/master/packages/casl-react/README.md Wraps the application or a part of it with AbilityProvider to make the ability instance available via context. ```jsx import { AbilityProvider } from '@casl/react'; import ability from './ability'; export default function App() { return ( ) } ``` -------------------------------- ### Alias Directionality Example Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/define-aliases/en.md Demonstrates that aliases are one-directional. Defining 'modify' as an alias for 'update' and 'delete' does not mean 'update' or 'delete' can be checked using the 'modify' alias. ```typescript import { defineAbility, createAliasResolver } from '@casl/ability' const resolveAction = createAliasResolver({ modify: ['update', 'delete'] }); const ability = defineAbility((can) => { can(['update', 'delete'], 'Post'); }, { resolveAction }); ability.can('modify', 'Post'); // false <--- ability.can('update', 'Post'); // true ability.can('delete', 'Post'); // true ``` -------------------------------- ### Get Versioned Base Path Source: https://github.com/stalniy/casl/blob/master/docs-src/public/web-root/404.html Extracts the versioned base path (e.g., '/v7') from a URL pathname. If no version is found, it returns a default fallback version. ```javascript function getVersionBasePath(pathname, fallbackVersion) { var versionMatch = pathname.match(/^\/v\d+(?=\/|$)/); return versionMatch ? versionMatch[0] : fallbackVersion; } ``` -------------------------------- ### Get Relevant Rule for an Action Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/debugging-testing/en.md Use `relevantRuleFor` to retrieve the specific rule that allows or forbids an action on a subject. This method returns `null` if no rule matches. ```javascript import { defineAbility } from '@casl/ability'; const ability = defineAbility((can) => { can('read', 'Article'); }); const rule = ability.relevantRuleFor('read', 'Article'); // instance of internal `Rule` class ``` ```javascript const rule = ability.relevantRuleFor('update', 'Article'); // null ``` -------------------------------- ### Basic Usage of accessibleFieldsBy with Mongoose Models Source: https://github.com/stalniy/casl/blob/master/packages/casl-mongoose/README.md A concise example showing the direct usage of `accessibleFieldsBy` with a Mongoose `Post` model and a document instance, without relying on the `accessibleRecordsPlugin`. ```typescript import { accessibleFieldsBy } from '@casl/mongoose'; accessibleFieldsBy(ability).ofType(Post); const post = new Post(); accessibleFieldsBy(ability).of(post); ``` -------------------------------- ### Update Ability Rules Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/api/casl-ability/en.md Completely replace the existing rules of an Ability instance with a new set of rules. Use this to dynamically change permissions, for example, after login or logout. ```typescript import { Ability } from '@casl/ability'; const ability = new Ability([{ action: 'manage', subject: 'all' }]); ability.update([]); // took back all permissions ``` -------------------------------- ### Configure Prisma Client Output Path Source: https://github.com/stalniy/casl/blob/master/packages/casl-prisma/README.md Specify a custom directory for the Prisma client generator in your schema.prisma file. This is necessary for Prisma 7 and later when `@prisma/client` does not re-export project types. ```prisma generator client { provider = "prisma-client" output = "../src/generated/client" } ``` -------------------------------- ### Check Permissions in Templates using AbilityService Source: https://github.com/stalniy/casl/blob/master/packages/casl-angular/README.md Use the AbilityService to get an observable of the current Ability instance and check permissions within Angular templates using the async pipe. ```typescript @Component({ selector: 'my-home', template: ` @if (ability$ | async as ability) {

Home Page

@if (ability.can('create', 'Post')) { } } ` }) export class HomeComponent { readonly ability$: Observable; constructor(abilityService: AbilityService) { this.ability$ = abilityService.ability$; } } ``` -------------------------------- ### Prisma Configuration Source: https://github.com/stalniy/casl/blob/master/packages/casl-prisma/README.md Set up the Prisma configuration file with the schema path and database URL. This file is used by Prisma to manage database connections and schema definitions. ```typescript import { defineConfig } from 'prisma/config'; export default defineConfig({ schema: './schema.prisma', datasource: { url: process.env.DATABASE_URL! }, }); ``` -------------------------------- ### Alternative Rule Definition Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/debugging-testing/en.md This shows an alternative way to define rules for the same permission, illustrating why testing implementation details is problematic. ```javascript import { AbilityBuilder, createMongoAbility } from '@casl/ability'; export function defineRulesFor(user) { const { can, cannot, rules } = new AbilityBuilder(createMongoAbility); if (user.isAdmin) { can('manage', 'all'); } else { can('read', 'Article', { private: false }); } return rules; } ``` -------------------------------- ### Define Abilities for a Blog Website Source: https://github.com/stalniy/casl/blob/master/README.md Defines user abilities for a blog, including reading posts, managing own posts, and restrictions on deleting old posts. Requires importing AbilityBuilder and createMongoAbility. ```typescript import { AbilityBuilder, createMongoAbility } from '@casl/ability' import { User } from '../models'; // application specific interfaces /** * @param user contains details about logged in user: its id, name, email, etc */ function defineAbilitiesFor(user: User) { const { can, cannot, build } = new AbilityBuilder(createMongoAbility); // can read blog posts can('read', 'BlogPost'); // can manage (i.e., do anything) own posts can('manage', 'BlogPost', { author: user.id }); // cannot delete a post if it was created more than a day ago cannot('delete', 'BlogPost', { createdAt: { $lt: Date.now() - 24 * 60 * 60 * 1000 } }); return build(); }); ``` -------------------------------- ### Import CASL Ability from CDN (latest) Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/install/en.md Use a CDN to import the latest version of CASL Ability for prototyping or learning. This method uses ES modules. ```html ``` -------------------------------- ### CASL Claim Based Authorization Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/claim-authorization/en.md An example of claim-based authorization using CASL. It defines abilities based on actions and checks them using the `ability.cannot` method. This approach is more scalable and maintainable than manual checks. ```typescript import { AbilityBuilder, Ability } from '@casl/ability'; type AppAbility = Ability; type Actions = 'review' | 'publish' | 'read'; const { can, build } = new AbilityBuilder(Ability); can('review'); can('publish'); can('read'); const ability = build(); function publishArticle(article: object, ability: AppAbility) { if (ability.cannot('publish')) { throw new Error('You cannot publish articles'); } // logic to publish article } ``` -------------------------------- ### Create Ability with JSON Rules Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/define-rules/en.md Use `createMongoAbility` to initialize an ability instance with rules defined as JSON objects. This is useful for dynamic permissions or when receiving permissions over the network. ```javascript import { createMongoAbility } from '@casl/ability'; export default createMongoAbility([ { action: 'read', subject: 'Post' }, { inverted: true, action: 'delete', subject: 'Post', conditions: { published: true } } ]) ``` -------------------------------- ### Get Accessible Fields for Mongoose Model or Instance Source: https://github.com/stalniy/casl/blob/master/packages/casl-mongoose/README.md Demonstrates how to use `accessibleFieldsBy` to retrieve accessible fields for a Mongoose model type or a concrete subject instance. Requires `ability` object from CASL. ```typescript import { accessibleFieldsBy } from '@casl/mongoose'; import { Post } from './models'; accessibleFieldsBy(ability).ofType('Post') // returns accessible fields for Post model accessibleFieldsBy(ability).ofType(Post) // also possible to pass class if classes are used for rule definition accessibleFieldsBy(ability).of(new Post()) // returns accessible fields for Post model ``` -------------------------------- ### Custom Accessible Fields Extractor Source: https://github.com/stalniy/casl/blob/master/packages/casl-mongoose/README.md Provides a TypeScript example of how to define a custom `getSubjectTypeAllFieldsExtractor` to customize how `accessibleFieldsBy` determines all available fields for a subject type. This allows overriding the default behavior of using `Model.schema.paths`. ```typescript import { AnyMongoAbility, Generics } from "@casl/ability"; import { AccessibleFields, GetSubjectTypeAllFieldsExtractor } from "@casl/ability/extra"; import mongoose from 'mongoose'; const getSubjectTypeAllFieldsExtractor: GetSubjectTypeAllFieldsExtractor = (type) => { /** custom implementation of returning all fields */ }; export function accessibleFieldsBy( ability: T, action: Parameters[0] = 'read' ): AccessibleFields['abilities'], unknown[]>[1]> { return new AccessibleFields(ability, action, getSubjectTypeAllFieldsExtractor); } ``` -------------------------------- ### Create Ability Rules with AbilityBuilder Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/intro/en.md Illustrates using `AbilityBuilder` to construct rules programmatically before updating the Ability instance. This is an alternative to directly passing rule objects to `update`. ```javascript import { createMongoAbility, AbilityBuilder } from '@casl/ability'; const ability = createMongoAbility(); const { can, rules } = new AbilityBuilder(createMongoAbility); can('read', 'all'); ability.update(rules); ``` -------------------------------- ### Create Ability with Default Generic Parameters Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/typescript/en.md Demonstrates creating an ability instance using the `createMongoAbility` factory function with default generic parameters for actions and subjects. This provides basic type safety. ```typescript import { createMongoAbility, Subject, MongoQuery } from '@casl/ability'; type PossibleAbilities = [string, Subject]; type Conditions = MongoQuery; const ability = createMongoAbility(); ``` -------------------------------- ### Define Basic Article Read Permission Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/intro/en.md Define a basic ability to read articles that are published. This example shows how CASL distinguishes between checking permissions on a specific subject instance versus a subject type. ```javascript import { defineAbility } from '@casl/ability'; import { Article } from './entities'; const ability = defineAbility((can) => { can('read', 'Article', { published: true }) }); const article = new Article({ published: true }); ability.can('read', article); // (1) ability.can('do', 'SomethingUndeclared'); // (2) ability.can('read', 'Article'); // (3) ``` -------------------------------- ### Define Articles for Users Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/cookbook/roles-with-persisted-permissions/en.md Creates article objects for both admin and author users. This step is preparatory for testing permissions related to article creation. ```typescript // imports here export default async function main() { // fetch users & create ability instances const adminArticle = { title: 'CASl and TypeScript', description: 'Is very powerful', authorId: admin!.id }; const authorArticle = { title: 'CASl and TypeScript', description: 'Is very powerful', authorId: author!.id }; // the rest of the code } ``` -------------------------------- ### Using 'do' and ':on' Aliases Source: https://github.com/stalniy/casl/blob/master/packages/casl-vue/README.md The 'do' and ':on' aliases can be used as alternatives to 'I' and 'a'/'an'/'this' respectively, though they may reduce code readability. ```html ... ... ``` -------------------------------- ### Get Permitted Fields with permittedFieldsOf Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/restricting-fields/en.md Uses the `permittedFieldsOf` helper to retrieve an array of fields a user is allowed to update on a specific article instance or subject type. Requires the ability definition and entity class. ```javascript import { permittedFieldsOf } from '@casl/ability/extra'; // Assuming 'ability', 'ownArticle', 'anotherArticle', and 'Article' are defined as in previous examples const ARTICLE_FIELDS = ['title', 'description', 'authorId', 'published']; const options = { fieldsFrom: rule => rule.fields || ARTICLE_FIELDS }; let fields = permittedFieldsOf(ability, 'update', ownArticle, options); // ['title', 'description'] fields = permittedFieldsOf(ability, 'update', anotherArticle, options); // [] fields = permittedFieldsOf(ability, 'update', 'Article', options); // ['title', 'description'] ! ``` -------------------------------- ### Retrieve Forbidden Reason for an Action Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/advanced/debugging-testing/en.md Use `relevantRuleFor` to get the rule associated with a forbidden action and then access its `reason` field to display the explanation to the user. Note that forbidden reasons do not support direct rules. ```javascript import { ability, article } from './defineAbilityWithReasons'; const rule = ability.relevantRuleFor('read', article({ private: true })); console.log(rule.reason); // Private content is protected by law ``` -------------------------------- ### Define Rules with AbilityBuilder Class Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/define-rules/en.md Use the `AbilityBuilder` class for defining rules, which avoids the nesting of `defineAbility` and is recommended for static permissions or custom ability factory functions. It requires importing `createMongoAbility`. ```javascript import { AbilityBuilder, createMongoAbility } from '@casl/ability' const { can, cannot, build } = new AbilityBuilder(createMongoAbility); can('read', 'Post'); cannot('delete', 'Post', { published: true }); export default build(); ``` -------------------------------- ### Update CASL Ability Instance on User Login Source: https://github.com/stalniy/casl/blob/master/packages/casl-vue/README.md Example of updating the CASL `Ability` instance dynamically after a user logs in. This typically involves fetching user data and defining new rules based on their role. ```html ``` -------------------------------- ### Define a Simple Action Alias Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/define-aliases/en.md Use `createAliasResolver` to map an alias like 'modify' to a list of actions such as 'update' and 'delete'. This alias can then be used in `defineAbility`. ```javascript import { defineAbility, createAliasResolver } from '@casl/ability' const resolveAction = createAliasResolver({ modify: ['update', 'delete'] }); const ability = defineAbility((can) => { can('modify', 'Post'); }, { resolveAction }); ability.can('modify', 'Post'); // true ability.can('update', 'Post'); // true ability.can('delete', 'Post'); // true ``` -------------------------------- ### Update Ability Rules Dynamically Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/intro/en.md Shows how to dynamically update an Ability instance's rules, for example, when a user logs in or out. An empty array forbids all actions, while a specific rule set can enable certain actions. ```javascript import ability from './defineAbility'; ability.update([]); // forbids everything ability.update([ // switch to readonly mode { action: 'read', subject: 'all' } ]); ``` -------------------------------- ### Subscribe to Ability Rule Updates Source: https://github.com/stalniy/casl/blob/master/docs-src/src/content/pages/guide/intro/en.md Demonstrates how to subscribe to `update` (before) and `updated` (after) events on an Ability instance to track changes to rules. The returned function unsubscribes the listener. ```javascript const unsubscribe = ability.on('update', ({ rules, target }) => { // `rules` is an array passed to `update` method // `target` is a Ability instance that triggered event }) unsubscribe() // removes subscription ```