@spacl/core
TypeScript icon, indicating that this package has built-in type declarations

1.2.1 • Public • Published

@spacl/core

npm version pipeline status coverage status standard-js

Simple path-based access control.

Installation

npm install @spacl/core

Additional Packages

This package contains only the core implementation; while it can be used standalone it was intended to be paired with one or more of the following companion packages:

Documentation

API documentation is available here.

Introduction

SPACL policies provide a declarative method of granting users permission to perform specific actions on specific paths within a hierarchy. A policy is made up of one or more rules, each of which declares a set of allowed and/or denied actions for a single path specification.

import { Rule, Policy } from '@spacl/core'

/* Create a policy describing a standard user who can
   view other user's profiles, and edit their own. */
const user = Policy.for('user',
  Rule.for('/user/+').allow('get'),
  Rule.for('/user/:name').allow('put'))

/* Create a derived policy describing an admin user who
   can also create, edit and delete any user's profile,
   but for safety reasons, cannot delete themselves. */
const admin = user.clone('admin').push(
  Rule.for('/user/+').allow('put', 'post', 'delete'),
  Rule.for('/user/:name').deny('delete'))

These policies can then be queried to see what access they grant for a particular combination of path, action, and optional query context, e.g. user name associated with the request). The response to a query can be true (explicitly allowed), false (explicitly denied) or null (implicitly denied; not governed by this policy).

/* Query context for our hypothetical user, 'foo'. */
const ctx = { name: 'foo' }

/* What can 'foo' access if they are granted 'user' rights? */
user.query('/user/foo', 'get',    ctx) /* true; explicitly allowed */
user.query('/user/foo', 'put',    ctx) /* true; explicitly allowed */
user.query('/user/foo', 'delete', ctx) /* null; implicitly denied */
user.query('/user/bar', 'get',    ctx) /* true; explicitly allowed */
user.query('/user/bar', 'put',    ctx) /* null; implicitly denied */
user.query('/user/bar', 'delete', ctx) /* null; implicitly denied */

/* Alternatively, what if 'foo' is granted 'admin' rights? */
admin.query('/user/foo', 'get',    ctx) /* true; explicitly allowed */
admin.query('/user/foo', 'put',    ctx) /* true; explicitly allowed */
admin.query('/user/foo', 'delete', ctx) /* false; explicitly denied */
admin.query('/user/bar', 'get',    ctx) /* true; explicitly allowed */
admin.query('/user/bar', 'put',    ctx) /* true; explicitly allowed */
admin.query('/user/bar', 'delete', ctx) /* true; explicitly allowed */

Path Specifications

Each rule in a policy is associated with a path specification, and will only apply to queries matching that specification. A path specification can be either an explicit, literal path, or a pattern matching multiple paths. The following substitutions can be used to represent one or more whole path segments:

  • + - Match-one wildcard; accepts exactly one path segment.
  • * - Match-many wildcard; accepts one or more path segments.
  • ++ - Match-one-or-none wildcard; accepts zero or one path segments.
  • ** - Match-many-or-none wildcard; accepts zero or more path segments.
  • :<prop> - Capture segment; accepts exactly one path segment matching the value of the named property within the current query context.

Substitutions can be combined as needed and placed anywhere within a path specification, not just at the end. Here are some basic examples:

  • /user/foo - Matches the exact path /user/foo.
  • /user/+ - Matches any path immediately under /user, e.g. /user/foo or /user/bar.
  • /user/* - Matches any path at any depth under /user, e.g. /user/foo or /user/bar/boo/baz.
  • /user/**/admin - Matches any path at any depth under /user, provided the final path segment is admin, e.g. /user/foo/admin.
  • /user/:id - Matches any path immediately under /user, provided the final path segment is equal to the value of the property id within the current query context, e.g. /user/foo given a query context of { id: 'foo' }.

Implicit Denial

Policies and rules are deny-by-default; if no rule within a policy applies to a particular combination of path and action, that combination is considered to be implicitly denied. By extension, an empty policy grants no permissions.

Explicit Denial

Policies and rules prioritise explicit denials; if multiple rules within a policy apply to a particular combination of path and action and one of them explicitly denies access that rule will override all others, regardless of their order within the policy.

Package Sidebar

Install

npm i @spacl/core

Weekly Downloads

1

Version

1.2.1

License

ISC

Unpacked Size

26.6 kB

Total Files

15

Last publish

Collaborators

  • cptpackrat