Last active
April 29, 2026 16:27
-
-
Save ahoward/69252d48bb94aae9e2fefe45e065220e to your computer and use it in GitHub Desktop.
scoped roles vs flat roles — why can(user, action, scope) beats roles[]
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
| // ─── OLD WAY — flat roles on the user ──────────────────────────────────────── | |
| if (user.roles.includes('manager')) { | |
| // manager of what? no idea. this passes for managers of ANY property. | |
| await create_lot(property_id, params) | |
| } | |
| if (user.roles.includes('patrol') || user.roles.includes('admin')) { | |
| // patrol where? could be a different property entirely. | |
| await create_scan(lot_id, plate) | |
| } | |
| // a bug waiting to happen: | |
| // alice is manager of property A. she hits the API with property B's id. | |
| // old check passes. she just created a lot on someone else's property. | |
| // ─── NEW WAY — roles scoped to the thing ───────────────────────────────────── | |
| if (can(user, 'create_lot', property_id)) { | |
| await create_lot(property_id, params) | |
| } | |
| if (can(user, 'create_scan', property_id)) { | |
| await create_scan(lot_id, plate) | |
| } | |
| // alice is manager of property A, patrol at property B. | |
| // can(alice, 'create_lot', 'property-a') → true | |
| // can(alice, 'create_lot', 'property-b') → false ← caught | |
| // can(alice, 'create_scan', 'property-b') → true | |
| // can(alice, 'create_scan', 'property-a') → false ← caught |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment