Last active
July 17, 2025 17:02
-
-
Save mtvbrianking/c861ceb40d41a18119978dfe0c98d8cd to your computer and use it in GitHub Desktop.
CASL load user permissions from API on login
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Ability, subject } from "@casl/ability"; | |
const editorRole = { id: 1, name: 'Editor'}; | |
const adminRole = { id: 2, name: 'Admin' }; | |
const user = { id: 1, alias: "jdoe", name: "John Doe", role_id: 1 }; | |
const ability = new Ability(); | |
const rules = [ | |
{ | |
action: "view", | |
subject: "roles", | |
conditions: { | |
id: user.role_id | |
} | |
} | |
]; | |
ability.update(rules); | |
console.log("can('view roles')", ability.can("view", "roles")); | |
console.log( | |
"can('view editorRole')", | |
ability.can("view", subject("roles", editorRole)) | |
); | |
console.log( | |
"can('view adminRole')", | |
ability.can("view", subject("roles", adminRole)) | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Ability, subject } from "@casl/ability"; | |
const user = { id: 1, alias: "jdoe", name: "John Doe" }; | |
const ownPost = { user_id: user.id }; | |
const otherPost = { user_id: 2 }; | |
const ability = new Ability(); | |
// fetched from API | |
const rules = [ | |
{ | |
action: "view-any", | |
subject: "posts" | |
}, | |
{ | |
action: "view", | |
subject: "posts" | |
}, | |
{ | |
action: "create", | |
subject: "posts" | |
}, | |
{ | |
action: "update", | |
subject: "posts", | |
conditions: { | |
user_id: user.id | |
} | |
}, | |
{ | |
action: "delete", | |
subject: "posts", | |
conditions: { | |
user_id: user.id | |
} | |
} | |
]; | |
// update ability with backend permissions | |
ability.update(rules); | |
// console.log("can('view-any posts')", ability.can("view-any", "posts")); | |
// console.log("can('view posts')", ability.can("view", "posts")); | |
// console.log("can('create posts')", ability.can("create", "posts")); | |
// console.log("can('update posts')", ability.can("update", "posts")); | |
console.log("can('delete posts')", ability.can("delete", "posts")); | |
console.log( | |
"can('delete ownPost')", | |
ability.can("delete", subject("posts", ownPost)) | |
); | |
console.log( | |
"can('delete otherPost')", | |
ability.can("delete", subject("posts", otherPost)) | |
); |
A simpler implementation with Laravel Spatie permission example.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Limitations
CASL can't work with Laravel Policies i.e,
you can't pass policies conditions from the API to CASL as they are logical statements, not stored in the permissions database.
The API document must mention the available conditions - so that the frontend can hard code them
<div if="$can('view roles')"></div>
--- OK<div if="$can('view roles', subject('role', role))"></div>
--- Useless for frontend permissions<div if="role.id == user.role_id || $can('view roles')"></div>
--- Good; if the condition is known before handCodeSanbox - https://codesandbox.io/s/casl-permissions-from-backend-g6tob