npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@danmasta/rbac

v0.0.5

Published

Authorization helper for node apps

Downloads

13

Readme

RBAC

Role based access control helper for node apps

Features:

  • Easy to use
  • Define roles, permissions, and claims in a declarative way
  • Inherit permissions across roles
  • Map roles and permission sets to user claims
  • Authorize roles and permission sets against user claims
  • Includes helper middlewares for express apps
  • Supports RBAC and ABAC type flows
  • Wildcard support for permission definitions

About

I wanted a better way to handle authorization in node apps. There are plenty of tools to help with authentication from different identity providers such as passport, oauth, saml, oidc, etc. But after you authenticate how do you handle authorization of specific resources and routes based on those identity claims? I've seen a lot of applications do some sort of manual checking of session state and user claims on a per-route basis and in non-uniform ways. That pattern tends to be pretty error-prone and not very scalable or maintainable as the application grows. It can also be difficult to audit, change, or verify over time.

This package lets you declaratively define your permission sets with a very simple syntax. It supports heirarchical rules via permission inheritance and allows you to map those permissions to identity claims. It includes helper functions for express apps for authorizing against permissions and roles. It also supports wildcard matching for permission definitions.

Usage

Add rbac as a dependency for your app and install via npm

npm install @danmasta/rbac --save

Require the package in your app

const RBAC = require('@danmasta/rbac');

let rbac = RBAC(roles);

Add authorization to a route

app.use('/admin', rbac.isRole('admin'), router);

Options

name | type | description -----|------|------------ claims | string | What property on the req object to find claims. Default is 'user' roles | array | Role definitions to use for authorizing against. Default is undefined authorizeAgainst | string\|array | Which claims to use to authorize permissions against. If not set it will attempt to authorize against all claims. Default is undefined strict | boolean | Whether or not to allow multiple role mappings per claim. If true it will throw an error if there is more than one role defined for a claim set. Default is false

Methods

Name | Description -----|------------ authorizeByPermissions(claims, permissions, authorizeAgainst?) | Verify permissions against a set of claims. Accepts a set of claims, list of permissions, and optional claim key filter to authorize against. If more than one permission is provided it will succeed only if all permissions are verified. Returns a promise that resolves with claims or rejects with an AuthorizationError authorizeByRoles(claims, roles, authorizeByRoles?) | Verify roles against a set of claims. Accepts a set of claims, list of roles, and optional claim key filter to authorize against. If more than one role is provided it will succeed if any role is verified. Returns a promise that resolves with claims or rejects with an AuthorizationError isAuthorized(permissions, opts?) | Helper middleware for verifying permissions on routes. Accepts an optional options object of { permissions, authorizeAgainst, redirect }. Returns a middleware function isRole(roles, opts?) | Helper middleware for verifying roles on routes. Accepts an optional options object of { roles, authorizeAgainst, redirect }. Returns a middleware function isAuthenticated(opts?) | Helper middleware for checking authentication state. Expects a req.isAuthenticated() function to be set. Accepts an optional options object of { redirect }. Returns a middleware function express() | Helper middleware for setting functions on the req object and res.locals object for routes and view templates. Returns a middleware function

Note: The redirect option for middleware functions is used to set req.session.redirect on failure, if desired

Role Objects

Each role object has the following signature:

Properties

name | type | description -----|------|------------ id | string | ID for the role. Required or an error is thrown. Used to look up other roles by ID for permission inheritance. Default is undefined description | string | Description for the role. Default is undefined permissions | string\|array | Permissions for the role. Should be an array of strings: ['posts.edit', 'posts.view']. Default is undefined inherit | string\|array | Which role ids to inherit permissions from. Default is undefined claims | object | Key/value pairs of claim names and values: { groups: ['editor', 'viewer'] }. Default is undefined

Methods

Name | Description -----|------------ generatePermissionTree() | Generate the permission tree for the role. Recursively walks and merges inherited permissions. Returns a permissions object isAuthorized(permission) | Verifies whethere or not the role has a permission: role.isAuthorized('posts.edit'). Returns a boolean

Wildcards

When describing permissions you can use wildcards * to authorize patterns of resources. The syntax looks like:

  • * At the end of a permission matches anything after and including. If you want to set a superadmin type role you can just use * as the only permission
  • ** Explicitly matches all from this point, alias for using * at the end
  • *. Match anything one level deep

Wildcard Examples

String | Description -------|------------ * | Matches anything at any depth api.* | Matches any permission at any depth that begins with api api.*. | Matches any permission at 1 depth that begins with api. Matches api.status, but not api.status.db api.*.view | Matches any permission at 1 depth that begins with api and ends with view. Matches api.users.view, but not api.users or api.users.edit

Examples

Define roles, find claims on the req.user object, and authorize against the groups claim

const RBAC = require('@danmasta/rbac');

const roles = [
    {
        id: 'admin',
        inherit: undefined,
        permissions: [
            '*'
        ],
        claims: {
            groups: [
                'admin'
            ]
        }
    },
    {
        id: 'editor',
        inherit: [
            'viewer',
        ],
        permissions: [
            'api.*.edit',
            'posts.edit'
        ],
        claims: {
            groups: [
                'editor'
            ]
        }
    },
    {
        id: 'viewer',
        inherit: undefined,
        permissions: [
            'api.*.view',
            'api.*.list',
            'posts.view'
        ],
        claims: {
            groups: [
                'viewer'
            ]
        }
    }
];

const rbac = RBAC(roles, { claims: 'user', authorizeAgainst: 'groups' });

Secure resources and routes with middleware by permissions

let app = express();

app.get('/post/:id', rbac.isAuthorized('posts.view'), (req, res, next) => {
    res.render('post/index', req.params.id);
});

app.get('/post/:id/edit', rbac.isAuthorized('posts.edit'), (req, res, next) => {
    res.render('post/edit', req.params.id);
});

app.post('/api/post/:id/edit', rbac.isAuthorized('api.post.edit'), (req, res, next) => {
    res.json({ message: 'post udpated', id: req.params.id });
});

Secure all admin routes by role

let app = express();

app.use('/admin', rbac.isRole('admin'), require('./routes/admin'));

Add express helpers to req and res.locals objects

let app = express();

app.use(rbac.express());

Verify permissions inside a route handler function

let app = express();

app.use(rbac.express());

app.get('/post/:id', (req, res, next) => {

    req.isAuthorized('posts.view').then(() => {
        res.render('post/index', req.params.id);
    }).catch(err => {
        next(err);
    });

});

Testing

Tests are currently run using mocha and chai. To execute tests run npm run test. To generate unit test coverage reports run npm run coverage

Contact

If you have any questions feel free to get in touch