1<!DOCTYPE html> 2<html lang="en-US" dir="ltr"> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width,initial-scale=1"> 6 <title>Getting Started | feathers-casl</title> 7 <meta name="description" content="Add access control with CASL to your feathers application"> 8 <meta name="generator" content="VitePress v2.0.0-alpha.17"> 9 <link rel="preload stylesheet" href="/assets/style.BUHdsUFN.css" as="style"> 10 <link rel="preload stylesheet" href="/vp-icons.css" as="style"> 11 12
12<script type="module" src="/assets/app.CwQ1rY3O.js"></script>
12 13 <link rel="preload" href="/assets/inter-roman-latin.Cy4MYw_J.woff2" as="font" type="font/woff2" crossorigin=""> 14 <link rel="modulepreload" href="/assets/chunks/theme.BsDwXA-J.js"> 15 <link rel="modulepreload" href="/assets/chunks/framework.DWIwSZ-6.js"> 16 <link rel="modulepreload" href="/assets/getting-started.md.BlL7VB7m.lean.js"> 17 <link rel="icon" href="/favicon.ico"> 18
18<script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
18 19
19<script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
19 20 </head> 21 <body> 22 <div id="app"><div class="Layout" data-v-7ee4747a><!--[--><!--]--><!--[--><span tabindex="-1" data-v-56ddb84b></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-56ddb84b>Skip to content</a><!--]--><!----><header class="VPNav" data-v-7ee4747a data-v-8187dc6d><div class="VPNavBar has-sidebar top" data-v-8187dc6d data-v-17451696><div class="wrapper" data-v-17451696><div class="container" data-v-17451696><div class="title" data-v-17451696><div class="VPNavBarTitle has-sidebar" data-v-17451696 data-v-7f767ae5><a class="title" href="/" data-v-7f767ae5><!--[--><!--]--><!--[--><img class="VPImage logo" src="/img/logo.svg" alt data-v-f9fc7ca2><!--]--><span data-v-7f767ae5>feathers-casl</span><!--[--><!--]--></a></div></div><div class="content" data-v-17451696><div class="content-body" data-v-17451696><!--[--><!--]--><div class="VPNavBarSearch search" data-v-17451696 data-v-b115b792><!--[--><button type="button" class="VPNavBarSearchButton" aria-label="Search" aria-keyshortcuts="/ control+k meta+k" data-v-b115b792 data-v-32351076><span class="vpi-search" aria-hidden="true" data-v-32351076></span><span class="text" data-v-32351076>Search</span><span class="keys" aria-hidden="true" data-v-32351076><kbd class="key-cmd" data-v-32351076>â</kbd><kbd class="key-ctrl" data-v-32351076>Ctrl</kbd><kbd data-v-32351076>K</kbd></span></button><!----><!----><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-17451696 data-v-b1964aab><span id="main-nav-aria-label" class="visually-hidden" data-v-b1964aab> Main Navigation </span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-b1964aab data-v-48018a98><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-48018a98><span class="text" data-v-48018a98><!----><span data-v-48018a98>Ecosystem</span><span class="vpi-chevron-down text-icon" data-v-48018a98></span></span></button><div class="menu" data-v-48018a98><div class="VPMenu" data-v-48018a98 data-v-e21def72><div class="items" data-v-e21def72><!--[--><!--[--><div class="VPMenuLink" data-v-e21def72 data-v-328078e2><a class="VPLink link vp-external-link-icon" href="https://feathersjs.com/" target="_blank" rel="noreferrer" data-v-328078e2><!--[--><span data-v-328078e2>www.feathersjs.com</span><!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e21def72 data-v-328078e2><a class="VPLink link vp-external-link-icon" href="https://github.com/feathersjs/feathers" target="_blank" rel="noreferrer" data-v-328078e2><!--[--><span data-v-328078e2>Feathers Github Repo</span><!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e21def72 data-v-328078e2><a class="VPLink link vp-external-link-icon" href="https://github.com/feathersjs/awesome-feathersjs" target="_blank" rel="noreferrer" data-v-328078e2><!--[--><span data-v-328078e2>Awesome Feathersjs</span><!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-17451696 data-v-d0e9ddd6><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-d0e9ddd6 data-v-88d2d789 data-v-9ae567d2><span class="check" data-v-9ae567d2><span class="icon" data-v-9ae567d2><!--[--><span class="vpi-sun sun" data-v-88d2d789></span><span class="vpi-moon moon" data-v-88d2d789></span><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-17451696 data-v-b2135855 data-v-31833492><!--[--><a class="VPSocialLink no-icon" href="https://twitter.com/feathersjs" aria-label="twitter" target="_blank" rel="me noopener" data-v-31833492 data-v-fd5e6b74><span class="vpi-social-twitter"></span></a><a class="VPSocialLink no-icon" href="https://discord.gg/qa8kez8QBx" aria-label="discord" target="_blank" rel="me noopener" data-v-31833492 data-v-fd5e6b74><span class="vpi-social-discord"></span></a><a class="VPSocialLink no-icon" href="https://github.com/fratzinger/feathers-casl" aria-label="github" target="_blank" rel="me noopener" data-v-31833492 data-v-fd5e6b74><span class="vpi-social-github"></span></a>
22<!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-17451696 data-v-339e20dc data-v-48018a98><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-48018a98><span class="vpi-more-horizontal icon" data-v-48018a98></span></button><div class="menu" data-v-48018a98><div class="VPMenu" data-v-48018a98 data-v-e21def72><!----><!--[--><!--[--><!----><div class="group" data-v-339e20dc><div class="item appearance" data-v-339e20dc><p class="label" data-v-339e20dc>Appearance</p><div class="appearance-action" data-v-339e20dc><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-339e20dc data-v-88d2d789 data-v-9ae567d2><span class="check" data-v-9ae567d2><span class="icon" data-v-9ae567d2><!--[--><span class="vpi-sun sun" data-v-88d2d789></span><span class="vpi-moon moon" data-v-88d2d789></span><!--]--></span></span></button></div></div></div><div class="group" data-v-339e20dc><div class="item social-links" data-v-339e20dc><div class="VPSocialLinks social-links-list" data-v-339e20dc data-v-31833492><!--[--><a class="VPSocialLink no-icon" href="https://twitter.com/feathersjs" aria-label="twitter" target="_blank" rel="me noopener" data-v-31833492 data-v-fd5e6b74><span class="vpi-social-twitter"></span></a><a class="VPSocialLink no-icon" href="https://discord.gg/qa8kez8QBx" aria-label="discord" target="_blank" rel="me noopener" data-v-31833492 data-v-fd5e6b74><span class="vpi-social-discord"></span></a><a class="VPSocialLink no-icon" href="https://github.com/fratzinger/feathers-casl" aria-label="github" target="_blank" rel="me noopener" data-v-31833492 data-v-fd5e6b74><span class="vpi-social-github"></span></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-17451696 data-v-25aec7de><span class="container" data-v-25aec7de><span class="top" data-v-25aec7de></span><span class="middle" data-v-25aec7de></span><span class="bottom" data-v-25aec7de></span></span></button></div></div></div></div><div class="divider" data-v-17451696><div class="divider-line" data-v-17451696></div></div></div><!----></header><div class="VPLocalNav has-sidebar empty" data-v-7ee4747a data-v-8f3272e2><div class="container" data-v-8f3272e2><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-8f3272e2><span class="vpi-align-left menu-icon" data-v-8f3272e2></span><span class="menu-text" data-v-8f3272e2>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-8f3272e2 data-v-1cceb885><button data-v-1cceb885>Return to top</button><!----></div></div></div><aside class="VPSidebar" data-v-7ee4747a data-v-3151ed93><div class="curtain" data-v-3151ed93></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-3151ed93><span class="visually-hidden" id="sidebar-aria-label" data-v-3151ed93> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="no-transition group" data-v-862074ed><section class="VPSidebarItem level-0 has-active" data-v-862074ed data-v-9957c532><div class="item" role="button" tabindex="0" data-v-9957c532><div class="indicator" data-v-9957c532></div><h2 class="text" data-v-9957c532>Guide</h2><!----></div><div class="items" data-v-9957c532><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9957c532><div class="item" data-v-9957c532><div class="indicator" data-v-9957c532></div><a class='VPLink link link' data-v-9957c532 href='/getting-started'><!--[--><p class="text" data-v-9957c532>Getting Started</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9957c532><div class="item" data-v-9957c532><div class="indicator" data-v-9957c532></div><a class='VPLink link link' data-v-9957c532 href='/hooks'><!--[--><p class="text" data-v-9957c532>Hooks</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9957c532><div class="item" data-v-9957c532><div class="indicator" data-v-9957c532></div><a class='VPLink link link' data-v-9957c532 href='/channels'><!--[--><p class="text" data-v-9957c532>Channels</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9957c532><div class="item" data-v-9957c532><div class="indicator" data-v-9957c532></div><a class='VPLink link link' data-v-9957c532 href='/utils'><!--[--><p class="text" data-v-9957c532>Utils</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9957c532><div class="item" data-v-9957c532><div class="indicator" data-v-9957c532></div><a class='VPLink link link' data-v-9957c532 href='/client-side'><!--[--><p class="text" data-v-9957c532>Client Side</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9957c532><div class="item" data-v-9957c532><div class="indicator" data-v-9957c532></div><a class='VPLink link link' data-v-9957c532 href='/gotchas'><!--[--><p class="text" data-v-9957c532>Gotchas</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9957c532><div class="item" data-v-9957c532><div class="indicator" data-v-9957c532></div><a class='VPLink link link' data-v-9957c532 href='/cookbook'><!--[--><p class="text" data-v-9957c532>Cookbook</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-7ee4747a data-v-70980a40><div class="VPDoc has-sidebar has-aside" data-v-70980a40 data-v-7da62fb4><!--[--><!--]--><div class="container" data-v-7da62fb4><div class="aside" data-v-7da62fb4><div class="aside-curtain" data-v-7da62fb4></div><div class="aside-container" data-v-7da62fb4><div class="aside-content" data-v-7da62fb4><div class="VPDocAside" data-v-7da62fb4 data-v-7808de11><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-7808de11 data-v-3c649ff1><div class="content" data-v-3c649ff1><div class="outline-marker" data-v-3c649ff1></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-3c649ff1>On this page</div><ul class="VPDocOutlineItem root" data-v-3c649ff1 data-v-a8515184><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-7808de11></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-7da62fb4><div class="content-container" data-v-7da62fb4><!--[--><!--]--><main class="main" data-v-7da62fb4><div style="position:relative;" class="vp-doc _getting-started" data-v-7da62fb4><div>
22<h1 id="getting-started" tabindex="-1">Getting Started <a class="header-anchor" href="#getting-started" aria-label="Permalink to âGetting Startedâ">â</a></h1><p align="center"><img src="/img/logo.svg" width="150"></p><p><a href="https://www.npmjs.com/package/feathers-casl" target="_blank" rel="noreferrer"><img src="https://img.shields.io/npm/v/feathers-casl" alt="npm"></a><a href="https://github.com/fratzinger/feathers-casl/actions" target="_blank" rel="noreferrer"><img src="https://github.com/fratzinger/feathers-casl/actions/workflows/node.js.yml/badge.svg" alt="Github CI"></a><a href="https://codeclimate.com/github/fratzinger/feathers-casl" target="_blank" rel="noreferrer"><img src="https://img.shields.io/codeclimate/maintainability/fratzinger/feathers-casl" alt="Code Climate maintainability"></a><a href="https://codeclimate.com/github/fratzinger/feathers-casl" target="_blank" rel="noreferrer"><img src="https://img.shields.io/codeclimate/coverage/fratzinger/feathers-casl" alt="Code Climate coverage"></a><a href="https://libraries.io/npm/feathers-casl" target="_blank" rel="noreferrer"><img src="https://img.shields.io/librariesio/release/npm/feathers-casl" alt="libraries.io"></a><a href="https://www.npmjs.com/package/feathers-casl" target="_blank" rel="noreferrer"><img src="https://img.shields.io/npm/dm/feathers-casl" alt="npm"></a><a href="https://github.com/fratzinger/feathers-casl/blob/main/LICENSE" target="_blank" rel="noreferrer"><img src="https://img.shields.io/github/license/fratzinger/feathers-casl" alt="GitHub license"></a><a href="https://discord.gg/qa8kez8QBx" target="_blank" rel="noreferrer"><img src="https://badgen.net/badge/icon/discord?icon=discord&label" alt="Discord"></a></p><h2 id="about" tabindex="-1">About <a class="header-anchor" href="#about" aria-label="Permalink to âAboutâ">â</a></h2><p>Add access control with CASL to your feathers application.</p><p>This project is built for <a href="http://feathersjs.com" target="_blank" rel="noreferrer">FeathersJS</a>. An open source web framework for building modern real-time applications. It's based on <a href="https://casl.js.org/" target="_blank" rel="noreferrer">CASL</a> and is a convenient layer to use <strong>CASL</strong> in your feathers.js-project. Supported versions: <code>@casl/ability^6</code> and <code>@feathersjs/feathers^5</code>.</p><h2 id="features" tabindex="-1">Features <a class="header-anchor" href="#features" aria-label="Permalink to âFeaturesâ">â</a></h2><ul><li>Fully powered by Feathers 5 & CASL 6</li><li>Allows permissions for all methods <code>create</code>, <code>find</code>, <code>get</code>, <code>update</code>, <code>patch</code>, <code>remove</code>, or <code>create</code>, <code>read</code>, <code>update</code>, <code>delete</code></li><li>Define permissions not based on methods: <code>can('view', 'Settings')</code> (Bring your custom logic)</li><li>Restrict by conditions: <code>can('create', 'Task', { userId: user.id })</code></li><li>Restrict by individual fields: <code>cannot('update', 'User', ['roleId'])</code></li><li>Native support for restrictive <code>$select</code>: <code>can('read', 'User', ['id', 'username'])</code> -> <code>$select: ['id', 'username']</code></li><li>Support to define abilities for anything (providers, users, roles, 3rd party apps, ...)</li><li>Fully supported adapters: <code>@feathersjs/knex</code>, <code>@feathersjs/memory</code>, <code>@feathersjs/mongodb</code>, <code>@fratzinger/feathers-kysely</code>, <code>feathers-sequelize</code>, not supported: <code>feathers-mongoose</code>, <code>feathers-nedb</code>, <code>feathers-objection</code></li><li>Support for dynamic rules stored in your database (Bring your own implementation ð )</li><li>hooks: <ul><li><code>checkBasicPermission</code> hook for client side usage as a before-hook</li><li><code>authorize</code> hook for complex rules</li><li>Disallow/allow <code>multi</code> methods (<code>create</code>, <code>patch</code>, <code>remove</code>) dynamically with: <code>can('remove-multi', 'Task', { userId: user.id })</code></li></ul></li><li>channels: <ul><li>every connection only receives updates based on rules</li><li><code>channels</code>-support also regards restrictive fields</li><li>rules can be defined individually for events</li></ul></li><li>utils: <ul><li><code>checkCan</code> to be used in hooks to check authorization before operations</li></ul></li><li>Baked in support for <code>@casl/angular</code>, <code>@casl/react</code>, <code>@casl/vue</code> and <code>@casl/aurelia</code></li></ul><h2 id="installation" tabindex="-1">Installation <a class="header-anchor" href="#installation" aria-label="Permalink to âInstallationâ">â</a></h2><div class="language-bash"><button title="Copy Code" class="copy"></button><span class="lang">bash</span>
22<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># npm</span></span> 23<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> i</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> feathers-casl</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @casl/ability</span></span> 24<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># yarn</span></span> 25<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">yarn</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> feathers-casl</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @casl/ability</span></span> 26<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># pnpm</span></span> 27<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> i</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> feathers-casl</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @casl/ability</span></span></code></pre></div><h2 id="getting-started-1" tabindex="-1">Getting Started <a class="header-anchor" href="#getting-started-1" aria-label="Permalink to âGetting Startedâ">â</a></h2><h3 id="provide-app-wide-feathers-casl-options" tabindex="-1">Provide app wide <code>feathers-casl</code> options <a class="header-anchor" href="#provide-app-wide-feathers-casl-options" aria-label="Permalink to âProvide app wide feathers-casl optionsâ">â</a></h3><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// app.ts</span></span> 28<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { feathersCasl } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "feathers-casl"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 29<span class="line"></span> 30<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">app.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">configure</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">feathersCasl</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">());</span></span></code></pre></div><p>The <code>feathersCasl()</code> function can be configured, to provide app wide options to <code>feathers-casl</code></p><h3 id="define-static-rules" tabindex="-1">Define static rules <a class="header-anchor" href="#define-static-rules" aria-label="Permalink to âDefine static rulesâ">â</a></h3><p>For most cases we want to define rules per user (or per user-role). So we first add a function which returns an <code>ability</code> from <code>@casl/ability</code> with these rules:</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// src/services/authentication/authentication.abilities.ts</span></span> 31<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">
31import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { Ability, AbilityBuilder, createAliasResolver } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@casl/ability"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 32<span class="line"></span> 33<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// don't forget this, as `read` is used internally</span></span> 34<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> resolveAction</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> createAliasResolver</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span> 35<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> update: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"patch"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// define the same rules for update & patch</span></span> 36<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> read: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"get"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"find"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// use 'read' as a equivalent for 'get' & 'find'</span></span> 37<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> delete: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"remove"</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // use 'delete' or 'remove'</span></span> 38<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span> 39<span class="line"></span> 40<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineRulesFor</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">user</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 41<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // also see https://casl.js.org/v6/en/guide/define-rules</span></span> 42<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">can</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cannot</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">rules</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> AbilityBuilder</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(Ability);</span></span> 43<span class="line"></span> 44<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (user.role </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&&</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> user.role.name </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "SuperAdmin"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span> 45<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // SuperAdmin can do evil</span></span> 46<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> can</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"manage"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"all"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span> 47<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> rules;</span></span> 48<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 49<span class="line"></span> 50<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (user.role </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&&</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> user.role.name </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "Admin"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span> 51<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> can</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"create"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"users"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span> 52<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 53<span class="line"></span> 54<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> can</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"read"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"users"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span> 55<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> can</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"update"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"users"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { id: user.id });</span></span> 56<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> cannot</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"update"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"users"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">
56, [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"roleId"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], { id: user.id });</span></span> 57<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> cannot</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"delete"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"users"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { id: user.id });</span></span> 58<span class="line"></span> 59<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> can</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"manage"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"tasks"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { userId: user.id });</span></span> 60<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> can</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"create-multi"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"posts"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { userId: user.id });</span></span> 61<span class="line"></span> 62<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> rules;</span></span> 63<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">};</span></span> 64<span class="line"></span> 65<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineAbilitiesFor</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">user</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 66<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> rules</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineRulesFor</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(user);</span></span> 67<span class="line"></span> 68<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Ability</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(rules, { resolveAction });</span></span> 69<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">};</span></span></code></pre></div><h3 id="add-abilities-to-hooks-context" tabindex="-1">Add abilities to hooks context <a class="header-anchor" href="#add-abilities-to-hooks-context" aria-label="Permalink to âAdd abilities to hooks contextâ">â</a></h3><p><code>feathers-casl</code> by default looks for <code>context.params.ability</code> in the <code>authorize</code>-hook and <code>connection.ability</code> in the channels. You want to <code>authorize</code> users who are <code>authenticated</code> first with <code>@feathers/authentication</code>. We can add hooks to the <code>/authentication</code> service to populate things to <code>context.params</code> and <code>connection</code> under the hood. We use this here to put <code>ability</code> on these objects, which makes it available to all hooks after the <code>authenticate(...)</code>-hook. This way we can define rules in just one place: ``</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span>
69<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// src/services/authentication/authentication.hooks.ts</span></span> 70<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineAbilitiesFor } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "./abilities"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 71<span class="line"></span> 72<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 73<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> before: {</span></span> 74<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> all: [],</span></span> 75<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> find: [],</span></span> 76<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> get: [],</span></span> 77<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> create: [],</span></span> 78<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> update: [],</span></span> 79<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> patch: [],</span></span> 80<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remove: []</span></span> 81<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span> 82<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> after: {</span></span> 83<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> all: [],</span></span> 84<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> find: [],</span></span> 85<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> get: [],</span></span> 86<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> create: [</span></span> 87<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">context</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 88<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">user</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> context.result;</span></span> 89<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">user) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> context;</span></span> 90<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> ability</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineAbilitiesFor</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(user);</span></span> 91<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> context.result.ability </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ability;</span></span> 92<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> context.result.rules </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ability.rules;</span></span> 93<span class="line"></span> 94<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> context;</span></span> 95<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 96<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span> 97<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> update: [],</span></span> 98<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> patch: [],</span></span> 99<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remove: []</span></span> 100<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span> 101<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> error: {</span></span> 102<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> all: [],</span></span> 103<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> find: [],</span></span> 104<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> get: [],</span></span> 105<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> create: [],</span></span> 106<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> update: [],</span></span> 107<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> patch: [],</span></span> 108<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remove: []</span></span> 109<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 110<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">};
110</span></span></code></pre></div><h3 id="add-the-authorize-hook-to-the-services" tabindex="-1">Add the authorize-hook to the services <a class="header-anchor" href="#add-the-authorize-hook-to-the-services" aria-label="Permalink to âAdd the authorize-hook to the servicesâ">â</a></h3><p>The <code>authorize</code>-hook can be used for all methods and has support for <code>multi: true</code>. You should use it as a <code>before</code> <strong>AND</strong> a <code>after</code> hook at the same time. For more information, see: <a href='/hooks#authorize'>authorize hook</a></p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// src/services/tasks/tasks.hooks.ts</span></span> 111<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { authenticate } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "@feathersjs/authentication"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 112<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { authorize } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "feathers-casl"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 113<span class="line"></span> 114<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// CAUTION! Make sure the adapter name fits your adapter (e.g. @feathersjs/mongodb, @feathersjs/knex, @fratzinger/feathers-kysely, feathers-sequelize, ...)!</span></span> 115<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// You'll want to have the `authorize` as an early before-hook (right after the `authenticate` hook) and as a late after hook, since it could modify the result based on the ability of the requesting user</span></span> 116<span class="line"></span> 117<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> authorizeHook</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> authorize</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ adapter: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"@feathersjs/mongodb"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span> 118<span class="line"></span> 119<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 120<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> before: {</span></span> 121<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> all: [</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">authenticate</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"jwt"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)],</span></span> 122<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> find: [authorizeHook],</span></span> 123<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> get: [authorizeHook],</span></span> 124<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> create: [authorizeHook],</span></span> 125<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> update: [authorizeHook],</span></span> 126<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> patch: [authorizeHook],</span></span> 127<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remove: [authorizeHook]</span></span> 128<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span> 129<span class="line"></span> 130<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> after: {</span></span> 131<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> all: [authorizeHook],</span></span> 132<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> find: [],</span></span> 133<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> get: [],</span></span> 134<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> create: [],</span></span> 135<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> update: [],</span></span> 136<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> patch: [],</span></span> 137<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remove: []</span></span> 138<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span> 139<span class="line"></span> 140<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> error: {</span></span> 141<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> all: [],</span></span> 142<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> find: [],</span></span> 143<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> get: [],</span></span> 144<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> create: [],</span></span> 145<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> update: [],</span></span> 146<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> patch: [],</span></span> 147<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remove: []</span></span> 148<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 149<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">};
149</span></span></code></pre></div><h3 id="filters-operators" tabindex="-1">Filters / Operators <a class="header-anchor" href="#filters-operators" aria-label="Permalink to âFilters / Operatorsâ">â</a></h3><p>For <code>feathers-casl</code> to work properly, you have to whitelist some operators in your service options. Also make sure to set the adapter option in your <code>authorize</code> hook like: <code>authorize({ adapter: '@feathersjs/mongodb' })</code></p><p><code>feathers-casl</code> merges the conditions of your rules into the incoming query. Inverted rules (<code>cannot(...)</code>) are expressed with <code>$nor</code>/<code>$not</code>, and whenever a rule condition and the query restrict the same property, both are combined with <code>$and</code>. Your service has to allow these operators:</p><ul><li><strong>@feathersjs/memory</strong>: <code>app.use('...', new Service({ filters: { $nor: true }, operators: ["$nor", "$and"] }))</code></li><li><strong>@feathersjs/mongodb</strong>: <code>app.use('...', new Service({ filters: { $nor: true }, operators: ["$nor", "$and"] }))</code></li><li><strong>@feathersjs/knex</strong>: nothing special to configure ð</li><li><strong>@fratzinger/feathers-kysely</strong>: expresses inverted (<code>cannot</code>) rules with <code>$not</code>, so this operator has to be allowed: <code>app.use('...', new KyselyService({ filters: { $not: true }, operators: ["$not", "$and"] }))</code></li><li><strong>feathers-sequelize</strong>: This one is a little bit different than the others. See the following:</li></ul><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { SequelizeService } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "feathers-sequelize"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 150<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { Op } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "sequelize"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 151<span class="line"></span> 152<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// ...</span></span> 153<span class="line"></span> 154<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">app.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">use</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span> 155<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "..."</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span> 156<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SequelizeService</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span> 157<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Model,</span></span> 158<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> operatorMap: {</span></span> 159<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> $not: Op.not</span></span> 160<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span> 161<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> filters: {</span></span> 162<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> $not: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span></span> 163<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span> 164<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> operators: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"$not"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">]</span></span> 165<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span> 166<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span></code></pre></div><h3 id="add-casl-to-channels" tabindex="-1">Add CASL to channels <a class="header-anchor" href="#add-casl-to-channels" aria-label="Permalink to âAdd CASL to channelsâ">â</a></h3><p>To unleash the full power of <code>feathers-casl</code> you want to add it to your <code>channels.js</code> so every user just gets updates only to items they can really read. It's as simple as the following example. For more information see: <a href='/channels'>channels</a></p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span>
166<pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// src/channels.ts</span></span> 167<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { getChannelsWithReadAbility, makeChannelOptions } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "feathers-casl"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 168<span class="line"></span> 169<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">app</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span> 170<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">typeof</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> app.channel </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!==</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> "function"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span> 171<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // If no real-time functionality has been configured just return</span></span> 172<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span> 173<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 174<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // ...</span></span> 175<span class="line"></span> 176<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> app.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">on</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"login"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">authResult</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">connection</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 177<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (connection) {</span></span> 178<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // this is needed to map the ability from the authentication hook to the connection so it gets available in the HookContext as `params.ability` automatically</span></span> 179<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (authResult.ability) {</span></span> 180<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> connection.ability </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> authResult.ability;</span></span> 181<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> connection.rules </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> authResult.rules;</span></span> 182<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 183<span class="line"></span> 184<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">
184 // ...</span></span> 185<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 186<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span> 187<span class="line"></span> 188<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // ...</span></span> 189<span class="line"></span> 190<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> caslOptions</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> makeChannelOptions</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(app);</span></span> 191<span class="line"></span> 192<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> app.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">publish</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">data</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">context</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 193<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getChannelsWithReadAbility</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(app, data, context, caslOptions);</span></span> 194<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span> 195<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h3 id="using-casl-with-the-rest-express-js-transport" tabindex="-1">Using CASL with the REST (Express.js) transport <a class="header-anchor" href="#using-casl-with-the-rest-express-js-transport" aria-label="Permalink to âUsing CASL with the REST (Express.js) transportâ">â</a></h3><p>In case you are not using sockets and want to use <code>feathers-casl</code> with the Express transport, you need to define the abilities right after your <code>authenticate()</code> hook and before the <code>authorize()</code> hook for each service relying on CASL.</p><div class="language-ts"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// src/services/tasks/tasks.hooks.ts</span></span> 196<span class="line"></span> 197<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 198<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> before: {</span></span> 199<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> all: [</span></span> 200<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> authenticate</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">"jwt"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">),</span></span> 201<span class="line"></span> 202<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // Add this to set abilities, if a user exists</span></span> 203<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">context</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span> 204<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">user</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> context.params;
204</span></span> 205<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (user) context.params.ability </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineAbilitiesFor</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(user);</span></span> 206<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> context;</span></span> 207<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 208<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ]</span></span> 209<span class="line"></span> 210<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // ...</span></span> 211<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span> 212<span class="line"></span> 213<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // ...</span></span> 214<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">};</span></span></code></pre></div><h2 id="testing" tabindex="-1">Testing <a class="header-anchor" href="#testing" aria-label="Permalink to âTestingâ">â</a></h2><p>Simply run <code>npm test</code> and all your tests in the <code>test/</code> directory will be run. The project has full support for <em>Visual Studio Code</em>. You can use the debugger to set breakpoints.</p><h2 id="help" tabindex="-1">Help <a class="header-anchor" href="#help" aria-label="Permalink to âHelpâ">â</a></h2><p>For more information on all the things you can do, visit <a href="http://docs.feathersjs.com" target="_blank" rel="noreferrer">FeathersJS</a> and <a href="https://casl.js.org/v6/en/" target="_blank" rel="noreferrer">CASL</a>.</p></div></div></main><footer class="VPDocFooter" data-v-7da62fb4 data-v-cec3e6e5><!--[--><!--]--><div class="edit-info" data-v-cec3e6e5><div class="edit-link" data-v-cec3e6e5><a class="VPLink link vp-external-link-icon no-icon edit-link-button" href="https://github.com/fratzinger/feathers-casl/edit/main/docs/getting-started.md" target="_blank" rel="noreferrer" data-v-cec3e6e5><!--[--><span class="vpi-square-pen edit-link-icon" data-v-cec3e6e5></span> Edit this page on GitHub<!--]--></a></div><!----></div><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-cec3e6e5><span class="visually-hidden" id="doc-footer-aria-label" data-v-cec3e6e5>Pager</span><div class="pager" data-v-cec3e6e5><!----></div><div class="pager" data-v-cec3e6e5><a class='VPLink link pager-link next' data-v-cec3e6e5 href='/hooks'><!--[--><span class="desc" data-v-cec3e6e5>Next page</span><span class="title" data-v-cec3e6e5>Hooks</span><!--]--></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><footer class="VPFooter has-sidebar" data-v-7ee4747a data-v-7325e293><div class="container" data-v-7325e293><p class="message" data-v-7325e293>Released under the MIT License.</p><p class="copyright" data-v-7325e293>Copyright © 2020-present Frederik Schmatz<br />This site is powered by <a href="https://www.netlify.com" target="blank">Netlify</a></p></div></footer><!--[--><!--]--></div></div> 215
215<script>window.__VP_HASH_MAP__=JSON.parse("{\"channels.md\":\"O1CseBp_\",\"client-side.md\":\"BIKoN4Mz\",\"cookbook.md\":\"CgOHqBSA\",\"getting-started.md\":\"BlL7VB7m\",\"gotchas.md\":\"BPwWJOEX\",\"hooks.md\":\"BF0jEmHj\",\"index.md\":\"Btq2ebLl\",\"utils.md\":\"CXwUvBvW\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"feathers-casl\",\"description\":\"Add access control with CASL to your feathers application\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"logo\":\"/img/logo.svg\",\"editLink\":{\"pattern\":\"https://github.com/fratzinger/feathers-casl/edit/main/docs/:path\",\"text\":\"Edit this page on GitHub\"},\"lastUpdatedText\":\"Last Updated\",\"socialLinks\":[{\"icon\":\"twitter\",\"link\":\"https://twitter.com/feathersjs\"},{\"icon\":\"discord\",\"link\":\"https://discord.gg/qa8kez8QBx\"},{\"icon\":\"github\",\"link\":\"https://github.com/fratzinger/feathers-casl\"}],\"sidebar\":[{\"text\":\"Guide\",\"items\":[{\"text\":\"Getting Started\",\"link\":\"/getting-started\"},{\"text\":\"Hooks\",\"link\":\"/hooks\"},{\"text\":\"Channels\",\"link\":\"/channels\"},{\"text\":\"Utils\",\"link\":\"/utils\"},{\"text\":\"Client Side\",\"link\":\"/client-side\"},{\"text\":\"Gotchas\",\"link\":\"/gotchas\"},{\"text\":\"Cookbook\",\"link\":\"/cookbook\"}]}],\"nav\":[{\"text\":\"Ecosystem\",\"items\":[{\"text\":\"www.feathersjs.com\",\"link\":\"https://feathersjs.com/\"},{\"text\":\"Feathers Github Repo\",\"link\":\"https://github.com/feathersjs/feathers\"},{\"text\":\"Awesome Feathersjs\",\"link\":\"https://github.com/feathersjs/awesome-feathersjs\"}]}],\"footer\":{\"message\":\"Released under the MIT License.\",\"copyright\":\"Copyright © 2020-present Frederik Schmatz<br />This site is powered by <a href=\\\"https://www.netlify.com\\\" target=\\\"blank\\\">Netlify</a>\"},\"search\":{\"provider\":\"algolia\",\"options\":{\"appId\":\"XJKV0V1N7U\",\"apiKey\":\"a4c3e7c6c2fcd7b1baa2ac04e17b9f72\",\"indexName\":\"feathers-casl\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false,\"additionalConfig\":{}}");</script>
215 216 217 </body> 218</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.