granted

0.2.3 • Public • Published

Granted

An object agnostic authorization layer for javascript. Features both a promise (recommended) and callback api for checking permissions.

account.grants(User, 'admin', function(user) {
  return (user.role === 'admin' || this.owner_id === user.id)
});
 
user.can('admin', account).then(function(user) {
  // .. the user is allowed to admin
}).catch(function(e) {
  // .. the user is not allowed to admin
});

Introduction:

Sometimes granting access between different objects gets hairy. You have edge cases and lots of ways that permissions can work and things end up being quite a mess.

Granted looks to simplify all of that, taking inspiration from projects like can can in ruby, it defines a few simple methods on an object, allowing us to reliably determine whether one object can perform an action on another.

Let's look at a simple example, say we have three objects, SuperUser, User and Document.

We want a document to be managed by any SuperUser, but only to a User if they have a "role" of "admin", or if they own the account. How would we do that?

First, we would define the granted permissions on the Account:

var doc = new Document({owner_id: 2, title: 'My Secret Account'});
 
// Allow any "authenticated" user to read the document.
doc.grants(User, 'read', function(user) {
  return user.isAuthenticated();
});
 
// Allow SuperUsers to do anything to the document.
doc.grants(SuperUser, ['read', 'write', 'destroy'], true);
 
// Allow Users to do anything to the document if they're
doc.grants(User, ['read', 'write', 'destroy'], function(user) {
 
  // Check that the user's ID matches with the owner_id of the document
  return user.id === this.get('owner_id')
});
 
// Allow anyone to read the metadata about an document, unless the
// object contains an is_robot flag.
doc.grants('readMeta', function(obj) {
  return obj.is_robot !== true;
});

Now, we can elsewhere call the can method on the object we're checking permissions on:

// Assumes `granted` has been mixed-in to each constructor
var su      = new SuperUser();
var authed  = new User({authenticated: true});
var user    = new User({id: 2});
var visitor = new Generic();
var robot   = new Generic({is_robot: true});
 
su.can('write', doc).then(function(su) {
  // ..
})
 
su.can('destroy', doc).then(function() {
  // ..
})
 
authed.can('read').then(function() {
  // true, because the user has been authed.
})
 
visitor.can('write', doc).catch(function(e) {
  // e instanceof granted.Errors.NotGranted
})
 
// or:
 
visitor.can('write', doc, function(e, visitor) {
  // e instanceof granted.Errors.NotGranted
});
 

API:

.grants([Constructor | predicate], name, predicate)

Grants the permission specified by name, (or permissions, if name is an array) if the predicate returns true, resolves with a successful promise, or

.can(name, [options]).then(...).catch(...)

.can(name, [options], callback)

.deny([Constructor | predicate], name, predicate)

.ungrant([Constructor | predicate], [name], [predicate])

.undeny([Constructor | predicate], [name], [predicate])

Package Sidebar

Install

npm i granted

Weekly Downloads

2

Version

0.2.3

License

MIT

Last publish

Collaborators

  • tgriesser