Permissions and patterns
Permissions are dot-separated segments, for example workspaces.create,
workspaces.1.read, or posts.comments.delete. Segments may contain any
character except ., and a permission cannot have empty segments:
^[^.]+(?:\.[^.]+)*$ // PermissionSchemaGranted permissions act as patterns: a granted permission implies a
requested one when every segment matches. A segment is a match when it is
equal, or when the granted segment is * (matches any single segment). A
trailing * matches any number of remaining segments, including none.
| Granted | Requested | Allowed |
|---|---|---|
workspaces.1.read |
workspaces.1.read |
yes |
workspaces.1.* |
workspaces.1.read |
yes |
workspaces.*.read |
workspaces.7.read |
yes |
workspaces.* |
workspaces.7.create |
yes |
workspaces.1.* |
workspaces.2.read |
no |
workspaces.1 |
workspaces.1.read |
no |
matchesPattern
Section titled “matchesPattern”The matcher is exported from @vperms/core (and re-exported by vperms):
import { matchesPattern } from "vperms";
matchesPattern("workspaces.1.*", "workspaces.1.read"); // truematchesPattern("workspaces.*.read", "workspaces.7.read"); // truematchesPattern("workspaces.1.*", "workspaces.2.read"); // falsematchesPattern(grantPattern, permission) is a pure, synchronous segment
comparison. It performs no inheritance and knows nothing about grants or
denies.
Specificity
Section titled “Specificity”When several grants match the same requested permission, the engine must decide
which one wins. It scores each pattern with permissionSpecificity:
- an exact segment adds 2,
- an inner
*adds 1, - a trailing
*adds 0.
import { permissionSpecificity } from "vperms";
permissionSpecificity("workspaces.1.read"); // 6permissionSpecificity("workspaces.*.read"); // 5permissionSpecificity("workspaces.1.*"); // 4permissionSpecificity("workspaces.*"); // 2More specific patterns win over broader wildcards. See Resolution for the full precedence order and how specificity combines with inheritance depth and source layer.
Matching a permission against grants
Section titled “Matching a permission against grants”matchPermission(grants, permission) returns the value of the best matching
grant, or null when nothing matches:
import { matchPermission } from "vperms";
const grants = [ { permission: "workspaces.*", value: true }, { permission: "workspaces.1.*", value: false },];
matchPermission(grants, "workspaces.1.read"); // false (more specific deny)matchPermission(grants, "workspaces.2.read"); // truematchPermission(grants, "posts.read"); // nullGrants are sorted with compareGrants first, so the result does not depend on
the order of the array.
Reserved permissions
Section titled “Reserved permissions”VeguiPerms reserves a small permission namespace for reading resolved permissions:
vperms.subject.me.permissions— always granted to every subject (at the lowest priority, so a deny can override it). Lets a subject read its own resolved permission set.vperms.subject.<subjectId>.permissions— permission to read another subject’s resolved set. Normal wildcards apply, e.g.vperms.subject.*.permissions.
import { subjectPermissionsPermission } from "vperms";
subjectPermissionsPermission("user"); // "vperms.subject.user.permissions"